CIRCT 24.0.0git
Loading...
Searching...
No Matches
ImportVerilogInternals.h
Go to the documentation of this file.
1//===- ImportVerilogInternals.h - Internal implementation details ---------===//
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// NOLINTNEXTLINE(llvm-header-guard)
10#ifndef CONVERSION_IMPORTVERILOG_IMPORTVERILOGINTERNALS_H
11#define CONVERSION_IMPORTVERILOG_IMPORTVERILOGINTERNALS_H
12
13#include "CaptureAnalysis.h"
22#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
23#include "mlir/Dialect/Func/IR/FuncOps.h"
24#include "slang/ast/ASTVisitor.h"
25#include "slang/ast/TimingControl.h"
26#include "slang/text/SourceManager.h"
27#include "llvm/ADT/ScopedHashTable.h"
28#include "llvm/Support/Debug.h"
29#include <map>
30#include <queue>
31
32#define DEBUG_TYPE "import-verilog"
33
34namespace circt {
35namespace ImportVerilog {
36
37using moore::Domain;
38
39/// Get the slang canonical body for the given `instance`, if there is one.
40/// If there isn't one, fall back to the normal body.
41inline const slang::ast::InstanceBodySymbol *
42getCanonicalBody(const slang::ast::InstanceSymbol &inst) {
43 const slang::ast::InstanceBodySymbol *body = inst.getCanonicalBody();
44 return body == nullptr ? &inst.body : body;
45}
46
47/// Port lowering information.
49 const slang::ast::PortSymbol &ast;
50 Location loc;
51 BlockArgument arg;
52 /// Slot index in the module signature. `outputIdx` is set for outputs;
53 /// `inputIdx` is set for inputs and inouts. Regular and expanded
54 /// interface-modport ports share one numbering per direction.
55 std::optional<unsigned> outputIdx;
56 std::optional<unsigned> inputIdx;
57};
58
59/// Lowering information for a single signal flattened from an interface port.
61 StringAttr name;
63 mlir::Type type;
64 Location loc;
65 BlockArgument arg;
66 /// the origin interface port symbol this was flattened from.
67 const slang::ast::InterfacePortSymbol *origin;
68 /// the interface body member (VariableSymbol , NetSymbol)
69 const slang::ast::Symbol *bodySym;
70 /// The connected interface instance backing this port (if any). This enables
71 /// materializing virtual interface handles from interface ports.
72 const slang::ast::InstanceSymbol *ifaceInstance = nullptr;
73 /// For modport-typed iface ports, the ModportPortSymbol this was flattened
74 /// from. Slang resolves in-body accesses like `bus.member` to a
75 /// `HierarchicalValueExpression` whose symbol is the `ModportPortSymbol`,
76 /// not the underlying interface body variable, so we register both keys in
77 /// `valueSymbols` to make the lookup find this port's `BlockArgument`.
78 const slang::ast::Symbol *modportPortSym = nullptr;
79 /// Slot index in the module signature; see `PortLowering::outputIdx`.
80 std::optional<unsigned> outputIdx;
81 std::optional<unsigned> inputIdx;
82};
83
84/// Lowering information for an expanded interface instance. Maps each interface
85/// body member to its expanded SSA value (moore.variable or moore.net).
87 DenseMap<const slang::ast::Symbol *, Value> expandedMembers;
88 DenseMap<StringAttr, Value> expandedMembersByName;
89};
90
91/// Cached lowering information for representing SystemVerilog `virtual
92/// interface` handles as Moore types (a struct of references to interface
93/// members).
95 moore::UnpackedStructType type;
96 SmallVector<StringAttr, 8> fieldNames;
97};
98
99/// A mapping entry for resolving Slang virtual interface member accesses.
100///
101/// Slang may resolve `vif.member` expressions (where `vif` has a
102/// `VirtualInterfaceType`) directly to a `NamedValueExpression` for `member`.
103/// This table records which virtual interface base symbol that member access is
104/// rooted in, so ImportVerilog can materialize the appropriate Moore IR.
106 const slang::ast::ValueSymbol *base = nullptr;
107 /// The name of the field in the lowered virtual interface handle struct that
108 /// should be accessed for this member.
109 StringAttr fieldName;
110};
111
112/// Module lowering information.
114 moore::SVModuleOp op;
115 SmallVector<PortLowering> ports;
116 SmallVector<FlattenedIfacePort> ifacePorts;
117 DenseMap<const slang::syntax::SyntaxNode *, const slang::ast::PortSymbol *>
119 /// Number of explicit-port slots per direction. Hierarchical-name ports
120 /// are appended after these in the module signature.
121 unsigned numExplicitOutputs = 0;
122 unsigned numExplicitInputs = 0;
123};
124
125/// Function lowering information. The `op` field holds either a `func::FuncOp`
126/// (for SystemVerilog functions), a `moore::CoroutineOp` (for tasks), or a
127/// `moore::DPIFuncOp` (for DPI-imported functions), all accessed through the
128/// `FunctionOpInterface`.
130 mlir::FunctionOpInterface op;
131
132 /// The AST symbols captured by this function, determined by the capture
133 /// analysis pre-pass. These are added as extra parameters to the function
134 /// during declaration.
135 SmallVector<const slang::ast::ValueSymbol *, 4> capturedSymbols;
136
137 explicit FunctionLowering(mlir::FunctionOpInterface op) : op(op) {}
138};
139
140// Class lowering information.
142 circt::moore::ClassDeclOp op;
143 bool methodsFinalized = false;
144};
145
146/// Information about a loops continuation and exit blocks relevant while
147/// lowering the loop's body statements.
148struct LoopFrame {
149 /// The block to jump to from a `continue` statement.
151 /// The block to jump to from a `break` statement.
153};
154
155/// Hierarchical path information.
156/// The "hierName" means a different hierarchical name at different module
157/// levels.
158/// The "idx" means where the current hierarchical name is on the portlists.
159/// The "direction" means hierarchical names whether downward(In) or
160/// upward(Out).
162 mlir::StringAttr hierName;
163 std::optional<unsigned int> idx;
164 slang::ast::ArgumentDirection direction;
165
166 /// The symbols this path resolves to, each paired with the elaborated
167 /// instance body it was observed in. Sibling instances elaborate the same
168 /// logical variable to distinct symbol objects. The pairing lets instance
169 /// wiring bind each one to the right instance.
170 llvm::SmallVector<std::pair<const slang::ast::ValueSymbol *,
171 const slang::ast::InstanceBodySymbol *>,
172 2>
174};
175
176/// ImportVerilog Elaboration Phases for Hierarchical Names
177///
178/// Hierarchical name resolution is performed in four distinct phases:
179///
180/// 1. Collection: The `traverseInstanceBody` pass walks the Slang AST to
181/// identify all hierarchical references (e.g., `Top.sub.var`). It records
182/// these in `hierPaths` mapped by module body.
183///
184/// 2. Port Generation: In `convertModuleHeader`, we inspect `hierPaths` for
185/// the module and add corresponding input/output ports to the generated
186/// `moore.module` to allow cross-module communication.
187///
188/// 3. Wiring: In `Structure.cpp` during instance creation, we look up the
189/// canonical module body's `hierPaths` to determine which hierarchical
190/// values need to be passed as inputs or captured as outputs from the
191/// instance.
192///
193/// 4. Resolution: In `Expressions.cpp`, visitors for rvalues and lvalues
194/// resolve hierarchical names by first checking function captures (inside
195/// a function body the capture argument must be used to respect region
196/// isolation), then the instance-aware `hierValueSymbols` map, and finally
197/// standard scoped lookups.
198
199// A slang::SourceLocation for deterministic comparisons. Comparisons use the
200// buffer's sortKey rather than bufferId.
202 uint64_t sortKey;
203 size_t offset;
204
205 static LocationKey get(const slang::SourceLocation &loc,
206 const slang::SourceManager &mgr) {
207 return {
208 mgr.getSortKey(loc.buffer()),
209 loc.offset(),
210 };
211 }
212
213 std::strong_ordering operator<=>(const LocationKey &) const = default;
214 bool operator==(const LocationKey &) const = default;
215};
216
217/// A helper class to facilitate the conversion from a Slang AST to MLIR
218/// operations. Keeps track of the destination MLIR module, builders, and
219/// various worklists and utilities needed for conversion.
220struct Context {
222 slang::ast::Compilation &compilation, mlir::ModuleOp intoModuleOp,
223 const slang::SourceManager &sourceManager)
226 builder(OpBuilder::atBlockEnd(intoModuleOp.getBody())),
228 Context(const Context &) = delete;
229
230 /// Return the MLIR context.
231 MLIRContext *getContext() { return intoModuleOp.getContext(); }
232
233 /// Convert a slang `SourceLocation` into an MLIR `Location`.
234 Location convertLocation(slang::SourceLocation loc);
235 /// Convert a slang `SourceRange` into an MLIR `Location`.
236 Location convertLocation(slang::SourceRange range);
237
238 /// Convert a slang type into an MLIR type. Returns null on failure. Uses the
239 /// provided location for error reporting, or tries to guess one from the
240 /// given type. Types tend to have unreliable location information, so it's
241 /// generally a good idea to pass in a location.
242 Type convertType(const slang::ast::Type &type, LocationAttr loc = {});
243 Type convertType(const slang::ast::DeclaredType &type);
244
245 /// Convert hierarchy and structure AST nodes to MLIR ops.
246 LogicalResult convertCompilation();
247 /// Convert a module and its ports to an empty module op in the IR. Also adds
248 /// the op to the worklist of module bodies to be lowered. This acts like a
249 /// module "declaration", allowing instances to already refer to a module even
250 /// before its body has been lowered.
251 /// `module` must be the canonical module body if there is one.
252 ModuleLowering *
253 convertModuleHeader(const slang::ast::InstanceBodySymbol *module);
254 /// Convert a module's body to the corresponding IR ops. The module op must
255 /// have already been created earlier through a `convertModuleHeader` call.
256 /// `module` must be the canonical module body if there is one.
257 LogicalResult convertModuleBody(const slang::ast::InstanceBodySymbol *module);
258 LogicalResult convertPackage(const slang::ast::PackageSymbol &package);
259 FunctionLowering *
260 declareFunction(const slang::ast::SubroutineSymbol &subroutine);
261 LogicalResult defineFunction(const slang::ast::SubroutineSymbol &subroutine);
262 LogicalResult
263 convertPrimitiveInstance(const slang::ast::PrimitiveInstanceSymbol &prim);
264 ClassLowering *declareClass(const slang::ast::ClassType &cls);
265 LogicalResult buildClassProperties(const slang::ast::ClassType &classdecl);
266 LogicalResult materializeClassMethods(const slang::ast::ClassType &classdecl);
267 LogicalResult convertGlobalVariable(const slang::ast::VariableSymbol &var);
268
269 /// Get the helper function implementing one of the `name`, `next`, and `prev`
270 /// built-in methods for the given enum type, creating it on first use.
271 /// Returns null and emits an error if the helper cannot be created.
272 mlir::func::FuncOp
273 getOrCreateEnumHelper(const slang::ast::Type &type,
274 slang::parsing::KnownSystemName method, Location loc);
275
276 /// Convert a Slang virtual interface type into the Moore type used to
277 /// represent virtual interface handles. Populates internal caches so that
278 /// interface instance references can be materialized consistently.
279 FailureOr<moore::UnpackedStructType>
280 convertVirtualInterfaceType(const slang::ast::VirtualInterfaceType &type,
281 Location loc);
282
283 /// Materialize a Moore value representing a concrete interface instance as a
284 /// virtual interface handle. This only succeeds for the Slang
285 /// `VirtualInterfaceType` wrappers that refer to a real interface instance
286 /// (`isRealIface`).
287 FailureOr<Value>
288 materializeVirtualInterfaceValue(const slang::ast::VirtualInterfaceType &type,
289 Location loc);
290
291 /// Register the interface members of a virtual interface base symbol for use
292 /// in later expression conversion.
293 LogicalResult
294 registerVirtualInterfaceMembers(const slang::ast::ValueSymbol &base,
295 const slang::ast::VirtualInterfaceType &type,
296 Location loc);
297
298 /// Checks whether one class (actualTy) is derived from another class
299 /// (baseTy). True if it's a subclass, false otherwise.
300 bool isClassDerivedFrom(const moore::ClassHandleType &actualTy,
301 const moore::ClassHandleType &baseTy);
302
303 /// Tries to find the closest base class of actualTy that carries a property
304 /// with name fieldName. The location is used for error reporting.
305 moore::ClassHandleType
306 getAncestorClassWithProperty(const moore::ClassHandleType &actualTy,
307 StringRef fieldName, Location loc);
308
309 Value getImplicitThisRef() const {
310 return currentThisRef; // block arg added in declareFunction
311 }
312
313 /// Maps sampled value system calls to their corresponding clocks
314 DenseMap<const slang::ast::CallExpression *,
315 const slang::ast::TimingControl *>
317
318 /// Generates a map from sampled value system calls to clocks using Slang's
319 /// analysis
321
322 Value getIndexedQueue() const { return currentQueue; }
323
324 // Convert a statement AST node to MLIR ops.
325 LogicalResult convertStatement(const slang::ast::Statement &stmt);
326
327 // Convert an expression AST node to MLIR ops.
328 Value convertRvalueExpression(const slang::ast::Expression &expr,
329 Type requiredType = {});
330 Value convertLvalueExpression(const slang::ast::Expression &expr);
331
332 // Convert an assertion expression AST node to MLIR ops.
333 Value convertAssertionExpression(const slang::ast::AssertionExpr &expr,
334 Location loc);
335
336 // Convert a sampled value system call expression AST node to MLIR ops.
338 const slang::ast::CallExpression &expr,
339 const slang::ast::CallExpression::SystemCallInfo &info, Location loc);
340
341 // Traverse the whole AST to collect hierarchical names.
342 void traverseInstanceBody(const slang::ast::InstanceSymbol &symbol);
343
344 /// Build a composite key for hierValueSymbols from a hierarchical value
345 /// expression. Returns {firstInstanceSymbol, dottedHierName} or std::nullopt
346 /// if the expression has no instance path.
347 std::optional<std::pair<const slang::ast::InstanceSymbol *, mlir::StringAttr>>
348 buildHierValueKey(const slang::ast::HierarchicalValueExpression &expr);
349
350 /// If `sym` is captured by the function currently being converted, return the
351 /// value it is bound to (the capture block argument); otherwise return null.
352 Value resolveCapturedValue(const slang::ast::ValueSymbol &sym);
353
354 // Convert timing controls into a corresponding set of ops that delay
355 // execution of the current block. Produces an error if the implicit event
356 // control `@*` or `@(*)` is used.
357 LogicalResult convertTimingControl(const slang::ast::TimingControl &ctrl);
358 // Convert timing controls into a corresponding set of ops that delay
359 // execution of the current block. Then converts the given statement, taking
360 // note of the rvalues it reads and adding them to a wait op in case an
361 // implicit event control `@*` or `@(*)` is used.
362 LogicalResult convertTimingControl(const slang::ast::TimingControl &ctrl,
363 const slang::ast::Statement &stmt);
364
365 /// Helper function to convert a value to a MLIR I1 value.
366 Value convertToI1(Value value);
367
368 // Convert a slang timing control for LTL
369 Value convertLTLTimingControl(const slang::ast::TimingControl &ctrl,
370 const Value &seqOrPro);
371
372 /// Creates a delayed assignment based on the given TimingControl delay (or
373 /// without a delay if the TimingControl is null)
374 LogicalResult
375 assignPrimOutputWithDelay(Value outputVal, Value assignment,
376 const slang::ast::TimingControl *delay,
377 Location loc);
378
379 LogicalResult
380 convertMOSSwitchPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim);
381
382 LogicalResult
383 convertCMOSSwitchPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim);
384
385 LogicalResult
386 convertNInputPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim);
387
388 LogicalResult
389 convertNOutputPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim);
390
391 LogicalResult
392 convertFixedPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim);
393
394 LogicalResult
395 convertPullGatePrimitive(const slang::ast::PrimitiveInstanceSymbol &prim);
396
397 FailureOr<moore::SVModuleOp>
398 convertUserDefinedPrimitiveDef(const slang::ast::PrimitiveSymbol &primitive);
399
401 const slang::ast::PrimitiveInstanceSymbol &prim);
402
403 LogicalResult convertThreeStateGatePrimitive(
404 const slang::ast::PrimitiveInstanceSymbol &prim);
405
406 /// Helper function to convert a value to its "truthy" boolean value.
407 Value convertToBool(Value value);
408
409 /// Helper function to convert a value to its "truthy" boolean value and
410 /// convert it to the given domain.
411 Value convertToBool(Value value, Domain domain);
412
413 /// Helper function to convert a value to its simple bit vector
414 /// representation, if it has one. Otherwise returns null. Also returns null
415 /// if the given value is null.
416 Value convertToSimpleBitVector(Value value);
417
418 /// Helper function to convert a `PackedType` value to its simple bit
419 /// vector representation, with special handling for time values which
420 /// require scaling by the local timescale. If `fallible` is true,
421 /// conversion failures are reported by returning a null value without
422 /// emitting diagnostics.
423 Value materializePackedToSBVConversion(Value value, Location loc,
424 bool fallible);
425
426 /// Helper function to insert the necessary operations to cast a value from
427 /// one type to another. If `fallible` is true, conversion failures are
428 /// reported by returning a null value without emitting diagnostics.
429 Value materializeConversion(Type type, Value value, bool isSigned,
430 Location loc, bool fallible = false);
431
432 /// Helper function to materialize an `SVInt` as an SSA value.
433 Value materializeSVInt(const slang::SVInt &svint,
434 const slang::ast::Type &type, Location loc);
435
436 /// Helper function to materialize a real value as an SSA value.
437 Value materializeSVReal(const slang::ConstantValue &svreal,
438 const slang::ast::Type &type, Location loc);
439
440 /// Helper function to materialize a string as an SSA value.
441 Value materializeString(const slang::ConstantValue &string,
442 const slang::ast::Type &astType, Location loc);
443
444 /// Helper function to materialize an unpacked array of `SVInt`s as an SSA
445 /// value.
447 const slang::ConstantValue &constant,
448 const slang::ast::FixedSizeUnpackedArrayType &astType, Location loc);
449
450 /// Helper function to materialize a `ConstantValue` as an SSA value. Returns
451 /// null if the constant cannot be materialized.
452 Value materializeConstant(const slang::ConstantValue &constant,
453 const slang::ast::Type &type, Location loc);
454
455 /// Convert a list of string literal arguments with formatting specifiers and
456 /// arguments to be interpolated into a `!moore.format_string` value. Returns
457 /// failure if an error occurs. Returns a null value if the formatted string
458 /// is trivially empty. Otherwise returns the formatted string.
459 FailureOr<Value> convertFormatString(
460 std::span<const slang::ast::Expression *const> arguments, Location loc,
461 moore::IntFormat defaultFormat = moore::IntFormat::Decimal,
462 bool appendNewline = false);
463
464 /// Result of converting a scan format string. The final cursor of the
465 /// consuming chain and the list of (destination expression, scanned value,
466 /// matched flag) tuples to assign
469 SmallVector<std::tuple<const slang::ast::Expression *, Value, Value>>
471 };
472
473 /// Convert a scan format string into a consuming chain of `moore.scan.*`
474 /// operations starting from `initialCursor`. Each non-suppressed specifier
475 /// produces an entry in `assignments`; the caller is responsible for emitting
476 /// the corresponding `moore.blocking_assign` ops. Returns failur if an erro
477 /// occurs.
478 FailureOr<ScanStringResult>
479 convertScanString(StringRef formatStr, Value initialCursor,
480 std::span<const slang::ast::Expression *const> destinations,
481 Location loc);
482
483 /// Convert system function calls. Returns a null `Value` on failure after
484 /// emitting an error.
485 Value convertSystemCall(const slang::ast::SystemSubroutine &subroutine,
486 Location loc,
487 std::span<const slang::ast::Expression *const> args);
488
489 /// Convert sampled value system function calls with a single argument.
490 FailureOr<Value>
491 convertSampledValueCallArity1(const slang::ast::SystemSubroutine &subroutine,
492 Location loc, Value value, Type originalType,
493 Value clockVal);
494
495 /// Evaluate the constant value of an expression.
496 slang::ConstantValue evaluateConstant(const slang::ast::Expression &expr);
497
498 /// Convert the inside/set-membership expression.
499 Value convertInsideCheck(Value insideLhs, Location loc,
500 const slang::ast::Expression &expr);
501
503 slang::ast::Compilation &compilation;
504 mlir::ModuleOp intoModuleOp;
505 const slang::SourceManager &sourceManager;
506
507 /// The builder used to create IR operations.
508 OpBuilder builder;
509 /// A symbol table of the MLIR module we are emitting into.
510 SymbolTable symbolTable;
511
512 /// The top-level operations ordered by their Slang source location. This is
513 /// used to produce IR that follows the source file order.
514 std::map<LocationKey, Operation *> orderedRootOps;
515
516 /// How we have lowered modules to MLIR.
517 /// The keys must be the slang canonical module bodies where they exist.
518 DenseMap<const slang::ast::InstanceBodySymbol *,
519 std::unique_ptr<ModuleLowering>>
521
522 /// Expanded interface instances, keyed by the InstanceSymbol pointer.
523 /// Each entry maps body members to their expanded SSA values. Scoped
524 /// per-module so entries are cleaned up when a module's conversion ends.
526 llvm::ScopedHashTable<const slang::ast::InstanceSymbol *,
528 using InterfaceInstanceScope = InterfaceInstances::ScopeTy;
530 /// Owning storage for InterfaceLowering objects
531 /// because ScopedHashTable stores values by copy.
532 SmallVector<std::unique_ptr<InterfaceLowering>> interfaceInstanceStorage;
533
534 /// Module instances already emitted by the predeclaration pass. These are
535 /// skipped during the later source-order module-body walk to avoid emitting
536 /// duplicate instances.
537 DenseSet<const slang::ast::InstanceSymbol *> predeclaredInstances;
538
539 /// Cached virtual interface layouts (type + field order).
540 DenseMap<const slang::ast::InstanceBodySymbol *, VirtualInterfaceLowering>
542 DenseMap<const slang::ast::ModportSymbol *, VirtualInterfaceLowering>
544 /// A list of modules for which the header has been created, but the body has
545 /// not been converted yet.
546 std::queue<const slang::ast::InstanceBodySymbol *> moduleWorklist;
547
548 /// A list of functions for which the declaration has been created, but the
549 /// body has not been defined yet.
550 std::queue<const slang::ast::SubroutineSymbol *> functionWorklist;
551
552 /// Functions that have already been converted.
553 DenseMap<const slang::ast::SubroutineSymbol *,
554 std::unique_ptr<FunctionLowering>>
556
557 /// DPI-C export directives keyed by the SystemVerilog subroutine they expose.
558 DenseMap<const slang::ast::SubroutineSymbol *, std::string> dpiExportCNames;
559
560 /// Helper functions generated for the enum built-in methods, keyed by the
561 /// canonical enum type and the method they implement.
562 DenseMap<
563 std::pair<const slang::ast::EnumType *, slang::parsing::KnownSystemName>,
564 mlir::func::FuncOp>
566
567 /// Classes that have already been converted.
568 DenseMap<const slang::ast::ClassType *, std::unique_ptr<ClassLowering>>
570
571 /// A table of defined values, such as variables, that may be referred to by
572 /// name in expressions. The expressions use this table to lookup the MLIR
573 /// value that was created for a given declaration in the Slang AST node.
575 llvm::ScopedHashTable<const slang::ast::ValueSymbol *, Value>;
576 using ValueSymbolScope = ValueSymbols::ScopeTy;
578
579 /// A table mapping symbols for interface members accessed through a virtual
580 /// interface to the virtual interface base value symbol.
582 llvm::ScopedHashTable<const slang::ast::ValueSymbol *,
584 using VirtualInterfaceMemberScope = VirtualInterfaceMembers::ScopeTy;
586
587 /// A table of defined global variables that may be referred to by name in
588 /// expressions.
589 DenseMap<const slang::ast::ValueSymbol *, moore::GlobalVariableOp>
591 /// A list of global variables that still need their initializers to be
592 /// converted.
593 SmallVector<const slang::ast::ValueSymbol *> globalVariableWorklist;
594
595 /// Pre-computed capture analysis: maps each function to the set of non-local,
596 /// non-global variables it captures (directly or transitively).
598
599 /// Collect all hierarchical names used for the per module/instance.
600 /// The keys are the slang canonical instance bodies (or the real instance
601 /// if slang's getCanonicalBody() returned null).
602 DenseMap<const slang::ast::InstanceBodySymbol *, SmallVector<HierPathInfo>>
604
605 /// Persistent map for hierarchical value lookups. Keyed by a composite
606 /// of the instance symbol (the specific instance being wired, e.g., p1 or
607 /// p2) and the hierarchical path name (e.g., "child.child_val"). This
608 /// ensures instance-specific resolution even when Slang shares or doesn't
609 /// share instance bodies across multiple instances of the same module.
610 DenseMap<std::pair<const slang::ast::InstanceSymbol *, mlir::StringAttr>,
611 Value>
613
614 /// A stack of assignment left-hand side values. Each assignment will push its
615 /// lowered left-hand side onto this stack before lowering its right-hand
616 /// side. This allows expressions to resolve the opaque
617 /// `LValueReferenceExpression`s in the AST.
618 SmallVector<Value> lvalueStack;
619
620 /// A stack of loop continuation and exit blocks. Each loop will push the
621 /// relevant info onto this stack, lower its loop body statements, and pop the
622 /// info off the stack again. Continue and break statements encountered as
623 /// part of the loop body statements will use this information to branch to
624 /// the correct block.
625 SmallVector<LoopFrame> loopStack;
626
627 /// A listener called for every variable or net being read. This can be used
628 /// to collect all variables read as part of an expression or statement, for
629 /// example to populate the list of observed signals in an implicit event
630 /// control `@*`.
631 std::function<void(moore::ReadOp)> rvalueReadCallback;
632 /// A listener called for every variable or net being assigned. This can be
633 /// used to collect all variables assigned in a task scope.
634 std::function<void(mlir::Operation *)> variableAssignCallback;
635
636 /// Whether we are currently converting expressions inside a timing control,
637 /// such as `@(posedge clk)`. This is used by the implicit event control
638 /// callback to avoid adding reads from explicit event controls to the
639 /// implicit sensitivity list.
641
642 /// The time scale currently in effect.
643 slang::TimeScale timeScale;
644
645 /// Variable to track the value of the current function's implicit `this`
646 /// reference
647 Value currentThisRef = {};
648
649 /// The function currently being converted, if any. Used to give captured
650 /// symbols priority over module-level hierarchical values inside function
651 /// bodies.
653
654 /// Variable that tracks the queue which we are currently converting the index
655 /// expression for. This is necessary to implement the `$` operator, which
656 /// returns the index of the last element of the queue.
657 Value currentQueue = {};
658
659 /// The definition symbol of the module body currently being converted.
660 /// Used to resolve the `%l`/`%L` library binding format specifier.
661 const slang::ast::DefinitionSymbol *currentDefinition = nullptr;
662
663 /// Ensure that the global variables for `$monitor` state exist. This creates
664 /// the `__monitor_active_id` and `__monitor_enabled` globals on first call.
666
667 /// Ensure that the global variable for `$timeformat` state exists.
668 /// This creates the `__timeformat_state` global on first call.
670
671 /// Process any pending `$monitor` calls and generate the monitoring
672 /// procedures at module level.
673 LogicalResult flushPendingMonitors();
674
675 /// Global variable ops for `$monitor` state management. These are created on
676 /// demand by `ensureMonitorGlobals()`.
677 moore::GlobalVariableOp monitorActiveIdGlobal = nullptr;
678 moore::GlobalVariableOp monitorEnabledGlobal = nullptr;
679
680 /// Global variable ops for `$timeformat` state management. These are created
681 /// on demand by `ensureTimeFormatGlobal()`.
682 moore::GlobalVariableOp timeFormatGlobal = nullptr;
683
684 /// The next monitor ID to allocate. ID 0 is reserved for "no monitor active".
685 unsigned nextMonitorId = 1;
686
687 /// Information about a pending `$monitor` call that needs to be converted
688 /// after the current module's body has been processed.
690 unsigned id;
691 Location loc;
692 const slang::ast::CallExpression *call;
693 };
694
695 /// Pending `$monitor` calls that need to be converted at module level.
696 SmallVector<PendingMonitor> pendingMonitors;
697
698private:
699 /// Helper function to extract the commonalities in lowering of functions and
700 /// methods
702 declareCallableImpl(const slang::ast::SubroutineSymbol &subroutine,
703 mlir::StringRef qualifiedName,
704 llvm::SmallVectorImpl<Type> &extraParams);
705};
706
707/// Map an index into an array, with bounds `range`, to a bit offset of the
708/// underlying bit storage. This is a dynamic version of
709/// `slang::ConstantRange::translateIndex`.
710Value getSelectIndex(Context &context, Location loc, Value index,
711 const slang::ConstantRange &range);
712
713} // namespace ImportVerilog
714} // namespace circt
715#endif // CONVERSION_IMPORTVERILOG_IMPORTVERILOGINTERNALS_H
static std::unique_ptr< Context > context
const slang::ast::InstanceBodySymbol * getCanonicalBody(const slang::ast::InstanceSymbol &inst)
Get the slang canonical body for the given instance, if there is one.
Value getSelectIndex(Context &context, Location loc, Value index, const slang::ConstantRange &range)
Map an index into an array, with bounds range, to a bit offset of the underlying bit storage.
DenseMap< const slang::ast::SubroutineSymbol *, SmallSetVector< const slang::ast::ValueSymbol *, 4 > > CaptureMap
The result of capture analysis: for each function, the set of non-local, non-global variable symbols ...
Domain
The number of values each bit of a type can assume.
Definition MooreTypes.h:51
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Options that control how Verilog input files are parsed and processed.
Information about a pending $monitor call that needs to be converted after the current module's body ...
Result of converting a scan format string.
SmallVector< std::tuple< const slang::ast::Expression *, Value, Value > > assignments
A helper class to facilitate the conversion from a Slang AST to MLIR operations.
Value convertToI1(Value value)
Helper function to convert a value to a MLIR I1 value.
FunctionLowering * declareCallableImpl(const slang::ast::SubroutineSymbol &subroutine, mlir::StringRef qualifiedName, llvm::SmallVectorImpl< Type > &extraParams)
Helper function to extract the commonalities in lowering of functions and methods.
ModuleLowering * convertModuleHeader(const slang::ast::InstanceBodySymbol *module)
Convert a module and its ports to an empty module op in the IR.
FailureOr< ScanStringResult > convertScanString(StringRef formatStr, Value initialCursor, std::span< const slang::ast::Expression *const > destinations, Location loc)
Convert a scan format string into a consuming chain of moore.scan.
std::queue< const slang::ast::SubroutineSymbol * > functionWorklist
A list of functions for which the declaration has been created, but the body has not been defined yet...
void populateSampledValueClocks()
Generates a map from sampled value system calls to clocks using Slang's analysis.
Value convertLvalueExpression(const slang::ast::Expression &expr)
LogicalResult registerVirtualInterfaceMembers(const slang::ast::ValueSymbol &base, const slang::ast::VirtualInterfaceType &type, Location loc)
Register the interface members of a virtual interface base symbol for use in later expression convers...
Definition Types.cpp:474
Value materializeConstant(const slang::ConstantValue &constant, const slang::ast::Type &type, Location loc)
Helper function to materialize a ConstantValue as an SSA value.
SmallVector< LoopFrame > loopStack
A stack of loop continuation and exit blocks.
const slang::ast::DefinitionSymbol * currentDefinition
The definition symbol of the module body currently being converted.
llvm::ScopedHashTable< const slang::ast::InstanceSymbol *, InterfaceLowering * > InterfaceInstances
Expanded interface instances, keyed by the InstanceSymbol pointer.
LogicalResult convertModuleBody(const slang::ast::InstanceBodySymbol *module)
Convert a module's body to the corresponding IR ops.
slang::ConstantValue evaluateConstant(const slang::ast::Expression &expr)
Evaluate the constant value of an expression.
SmallVector< PendingMonitor > pendingMonitors
Pending $monitor calls that need to be converted at module level.
llvm::ScopedHashTable< const slang::ast::ValueSymbol *, VirtualInterfaceMemberAccess > VirtualInterfaceMembers
A table mapping symbols for interface members accessed through a virtual interface to the virtual int...
Value convertInsideCheck(Value insideLhs, Location loc, const slang::ast::Expression &expr)
Convert the inside/set-membership expression.
Value convertLTLTimingControl(const slang::ast::TimingControl &ctrl, const Value &seqOrPro)
LogicalResult materializeClassMethods(const slang::ast::ClassType &classdecl)
DenseMap< const slang::ast::ValueSymbol *, moore::GlobalVariableOp > globalVariables
A table of defined global variables that may be referred to by name in expressions.
slang::ast::Compilation & compilation
LogicalResult convertTimingControl(const slang::ast::TimingControl &ctrl)
DenseMap< const slang::ast::InstanceBodySymbol *, VirtualInterfaceLowering > virtualIfaceLowerings
Cached virtual interface layouts (type + field order).
LogicalResult flushPendingMonitors()
Process any pending $monitor calls and generate the monitoring procedures at module level.
LogicalResult convertNInputPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim)
LogicalResult assignPrimOutputWithDelay(Value outputVal, Value assignment, const slang::ast::TimingControl *delay, Location loc)
Creates a delayed assignment based on the given TimingControl delay (or without a delay if the Timing...
Context(const ImportVerilogOptions &options, slang::ast::Compilation &compilation, mlir::ModuleOp intoModuleOp, const slang::SourceManager &sourceManager)
OpBuilder builder
The builder used to create IR operations.
std::queue< const slang::ast::InstanceBodySymbol * > moduleWorklist
A list of modules for which the header has been created, but the body has not been converted yet.
LogicalResult convertGlobalVariable(const slang::ast::VariableSymbol &var)
Convert a variable to a moore.global_variable operation.
Value materializeFixedSizeUnpackedArrayType(const slang::ConstantValue &constant, const slang::ast::FixedSizeUnpackedArrayType &astType, Location loc)
Helper function to materialize an unpacked array of SVInts as an SSA value.
Value convertSampledValueCallExpression(const slang::ast::CallExpression &expr, const slang::ast::CallExpression::SystemCallInfo &info, Location loc)
DenseSet< const slang::ast::InstanceSymbol * > predeclaredInstances
Module instances already emitted by the predeclaration pass.
CaptureMap functionCaptures
Pre-computed capture analysis: maps each function to the set of non-local, non-global variables it ca...
DenseMap< const slang::ast::ClassType *, std::unique_ptr< ClassLowering > > classes
Classes that have already been converted.
std::function< void(moore::ReadOp)> rvalueReadCallback
A listener called for every variable or net being read.
bool isClassDerivedFrom(const moore::ClassHandleType &actualTy, const moore::ClassHandleType &baseTy)
Checks whether one class (actualTy) is derived from another class (baseTy).
Context(const Context &)=delete
LogicalResult convertUserDefinedPrimitiveInstance(const slang::ast::PrimitiveInstanceSymbol &prim)
void ensureTimeFormatGlobal()
Ensure that the global variable for $timeformat state exists.
Value convertSystemCall(const slang::ast::SystemSubroutine &subroutine, Location loc, std::span< const slang::ast::Expression *const > args)
Convert system function calls.
DenseMap< std::pair< const slang::ast::EnumType *, slang::parsing::KnownSystemName >, mlir::func::FuncOp > enumHelpers
Helper functions generated for the enum built-in methods, keyed by the canonical enum type and the me...
Type convertType(const slang::ast::Type &type, LocationAttr loc={})
Convert a slang type into an MLIR type.
Definition Types.cpp:224
DenseMap< const slang::ast::SubroutineSymbol *, std::unique_ptr< FunctionLowering > > functions
Functions that have already been converted.
Value materializeSVInt(const slang::SVInt &svint, const slang::ast::Type &type, Location loc)
Helper function to materialize an SVInt as an SSA value.
slang::TimeScale timeScale
The time scale currently in effect.
Value resolveCapturedValue(const slang::ast::ValueSymbol &sym)
If sym is captured by the function currently being converted, return the value it is bound to (the ca...
DenseMap< std::pair< const slang::ast::InstanceSymbol *, mlir::StringAttr >, Value > hierValueSymbols
Persistent map for hierarchical value lookups.
Value materializeSVReal(const slang::ConstantValue &svreal, const slang::ast::Type &type, Location loc)
Helper function to materialize a real value as an SSA value.
ClassLowering * declareClass(const slang::ast::ClassType &cls)
VirtualInterfaceMembers::ScopeTy VirtualInterfaceMemberScope
Value convertToBool(Value value)
Helper function to convert a value to its "truthy" boolean value.
LogicalResult convertFixedPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim)
std::function< void(mlir::Operation *)> variableAssignCallback
A listener called for every variable or net being assigned.
DenseMap< const slang::ast::SubroutineSymbol *, std::string > dpiExportCNames
DPI-C export directives keyed by the SystemVerilog subroutine they expose.
LogicalResult convertCMOSSwitchPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim)
mlir::func::FuncOp getOrCreateEnumHelper(const slang::ast::Type &type, slang::parsing::KnownSystemName method, Location loc)
Get the helper function implementing one of the name, next, and prev built-in methods for the given e...
moore::ClassHandleType getAncestorClassWithProperty(const moore::ClassHandleType &actualTy, StringRef fieldName, Location loc)
Tries to find the closest base class of actualTy that carries a property with name fieldName.
void ensureMonitorGlobals()
Ensure that the global variables for $monitor state exist.
FailureOr< moore::SVModuleOp > convertUserDefinedPrimitiveDef(const slang::ast::PrimitiveSymbol &primitive)
FailureOr< Value > convertFormatString(std::span< const slang::ast::Expression *const > arguments, Location loc, moore::IntFormat defaultFormat=moore::IntFormat::Decimal, bool appendNewline=false)
Convert a list of string literal arguments with formatting specifiers and arguments to be interpolate...
const ImportVerilogOptions & options
Value materializePackedToSBVConversion(Value value, Location loc, bool fallible)
Helper function to convert a PackedType value to its simple bit vector representation,...
Value convertRvalueExpression(const slang::ast::Expression &expr, Type requiredType={})
SmallVector< std::unique_ptr< InterfaceLowering > > interfaceInstanceStorage
Owning storage for InterfaceLowering objects because ScopedHashTable stores values by copy.
Value convertToSimpleBitVector(Value value)
Helper function to convert a value to its simple bit vector representation, if it has one.
moore::GlobalVariableOp monitorActiveIdGlobal
Global variable ops for $monitor state management.
LogicalResult convertMOSSwitchPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim)
VirtualInterfaceMembers virtualIfaceMembers
llvm::ScopedHashTable< const slang::ast::ValueSymbol *, Value > ValueSymbols
A table of defined values, such as variables, that may be referred to by name in expressions.
Value materializeString(const slang::ConstantValue &string, const slang::ast::Type &astType, Location loc)
Helper function to materialize a string as an SSA value.
DenseMap< const slang::ast::CallExpression *, const slang::ast::TimingControl * > sampledValueCallClocks
Maps sampled value system calls to their corresponding clocks.
moore::GlobalVariableOp monitorEnabledGlobal
DenseMap< const slang::ast::ModportSymbol *, VirtualInterfaceLowering > virtualIfaceModportLowerings
Value currentThisRef
Variable to track the value of the current function's implicit this reference.
const slang::SourceManager & sourceManager
Value materializeConversion(Type type, Value value, bool isSigned, Location loc, bool fallible=false)
Helper function to insert the necessary operations to cast a value from one type to another.
void traverseInstanceBody(const slang::ast::InstanceSymbol &symbol)
Value currentQueue
Variable that tracks the queue which we are currently converting the index expression for.
std::map< LocationKey, Operation * > orderedRootOps
The top-level operations ordered by their Slang source location.
FunctionLowering * currentFunctionLowering
The function currently being converted, if any.
InterfaceInstances::ScopeTy InterfaceInstanceScope
moore::GlobalVariableOp timeFormatGlobal
Global variable ops for $timeformat state management.
LogicalResult convertThreeStateGatePrimitive(const slang::ast::PrimitiveInstanceSymbol &prim)
FailureOr< Value > materializeVirtualInterfaceValue(const slang::ast::VirtualInterfaceType &type, Location loc)
Materialize a Moore value representing a concrete interface instance as a virtual interface handle.
Definition Types.cpp:357
LogicalResult convertPrimitiveInstance(const slang::ast::PrimitiveInstanceSymbol &prim)
Convert a primitive instance.
SymbolTable symbolTable
A symbol table of the MLIR module we are emitting into.
DenseMap< const slang::ast::InstanceBodySymbol *, SmallVector< HierPathInfo > > hierPaths
Collect all hierarchical names used for the per module/instance.
bool isInsideTimingControl
Whether we are currently converting expressions inside a timing control, such as @(posedge clk).
FunctionLowering * declareFunction(const slang::ast::SubroutineSymbol &subroutine)
Convert a function and its arguments to a function declaration in the IR.
LogicalResult convertNOutputPrimitive(const slang::ast::PrimitiveInstanceSymbol &prim)
Value convertAssertionExpression(const slang::ast::AssertionExpr &expr, Location loc)
LogicalResult buildClassProperties(const slang::ast::ClassType &classdecl)
std::optional< std::pair< const slang::ast::InstanceSymbol *, mlir::StringAttr > > buildHierValueKey(const slang::ast::HierarchicalValueExpression &expr)
Build a composite key for hierValueSymbols from a hierarchical value expression.
LogicalResult convertPackage(const slang::ast::PackageSymbol &package)
Convert a package and its contents.
LogicalResult convertCompilation()
Convert hierarchy and structure AST nodes to MLIR ops.
MLIRContext * getContext()
Return the MLIR context.
LogicalResult defineFunction(const slang::ast::SubroutineSymbol &subroutine)
Define a function’s body.
unsigned nextMonitorId
The next monitor ID to allocate. ID 0 is reserved for "no monitor active".
LogicalResult convertPullGatePrimitive(const slang::ast::PrimitiveInstanceSymbol &prim)
LogicalResult convertStatement(const slang::ast::Statement &stmt)
SmallVector< const slang::ast::ValueSymbol * > globalVariableWorklist
A list of global variables that still need their initializers to be converted.
FailureOr< Value > convertSampledValueCallArity1(const slang::ast::SystemSubroutine &subroutine, Location loc, Value value, Type originalType, Value clockVal)
Convert sampled value system function calls with a single argument.
FailureOr< moore::UnpackedStructType > convertVirtualInterfaceType(const slang::ast::VirtualInterfaceType &type, Location loc)
Convert a Slang virtual interface type into the Moore type used to represent virtual interface handle...
Definition Types.cpp:238
SmallVector< Value > lvalueStack
A stack of assignment left-hand side values.
DenseMap< const slang::ast::InstanceBodySymbol *, std::unique_ptr< ModuleLowering > > modules
How we have lowered modules to MLIR.
Location convertLocation(slang::SourceLocation loc)
Convert a slang SourceLocation into an MLIR Location.
Lowering information for a single signal flattened from an interface port.
const slang::ast::InterfacePortSymbol * origin
the origin interface port symbol this was flattened from.
const slang::ast::Symbol * modportPortSym
For modport-typed iface ports, the ModportPortSymbol this was flattened from.
const slang::ast::Symbol * bodySym
the interface body member (VariableSymbol , NetSymbol)
std::optional< unsigned > outputIdx
Slot index in the module signature; see PortLowering::outputIdx.
const slang::ast::InstanceSymbol * ifaceInstance
The connected interface instance backing this port (if any).
SmallVector< const slang::ast::ValueSymbol *, 4 > capturedSymbols
The AST symbols captured by this function, determined by the capture analysis pre-pass.
FunctionLowering(mlir::FunctionOpInterface op)
slang::ast::ArgumentDirection direction
llvm::SmallVector< std::pair< const slang::ast::ValueSymbol *, const slang::ast::InstanceBodySymbol * >, 2 > valueSyms
The symbols this path resolves to, each paired with the elaborated instance body it was observed in.
Lowering information for an expanded interface instance.
DenseMap< const slang::ast::Symbol *, Value > expandedMembers
DenseMap< StringAttr, Value > expandedMembersByName
ImportVerilog Elaboration Phases for Hierarchical Names.
bool operator==(const LocationKey &) const =default
static LocationKey get(const slang::SourceLocation &loc, const slang::SourceManager &mgr)
std::strong_ordering operator<=>(const LocationKey &) const =default
Information about a loops continuation and exit blocks relevant while lowering the loop's body statem...
Block * breakBlock
The block to jump to from a break statement.
Block * continueBlock
The block to jump to from a continue statement.
DenseMap< const slang::syntax::SyntaxNode *, const slang::ast::PortSymbol * > portsBySyntaxNode
SmallVector< FlattenedIfacePort > ifacePorts
unsigned numExplicitOutputs
Number of explicit-port slots per direction.
std::optional< unsigned > outputIdx
Slot index in the module signature.
const slang::ast::PortSymbol & ast
Cached lowering information for representing SystemVerilog virtual interface handles as Moore types (...
A mapping entry for resolving Slang virtual interface member accesses.
StringAttr fieldName
The name of the field in the lowered virtual interface handle struct that should be accessed for this...