mirror of https://github.com/llvm/circt.git
239 lines
9.8 KiB
C++
239 lines
9.8 KiB
C++
//===- 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/Moore/MooreOps.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;
|
|
};
|
|
|
|
/// Function lowering information.
|
|
struct FunctionLowering {
|
|
mlir::func::FuncOp op;
|
|
};
|
|
|
|
/// 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,
|
|
SmallDenseMap<slang::BufferID, StringRef> &bufferFilePaths)
|
|
: options(options), compilation(compilation), intoModuleOp(intoModuleOp),
|
|
sourceManager(sourceManager), bufferFilePaths(bufferFilePaths),
|
|
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);
|
|
LogicalResult convertPackage(const slang::ast::PackageSymbol &package);
|
|
FunctionLowering *
|
|
declareFunction(const slang::ast::SubroutineSymbol &subroutine);
|
|
LogicalResult convertFunction(const slang::ast::SubroutineSymbol &subroutine);
|
|
|
|
// 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);
|
|
|
|
// 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 a slang timing control into an MLIR timing control.
|
|
LogicalResult convertTimingControl(const slang::ast::TimingControl &ctrl,
|
|
const slang::ast::Statement &stmt);
|
|
|
|
/// 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 `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(
|
|
slang::span<const slang::ast::Expression *const> arguments, Location loc,
|
|
moore::IntFormat defaultFormat = moore::IntFormat::Decimal,
|
|
bool appendNewline = false);
|
|
|
|
/// 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;
|
|
SmallDenseMap<slang::BufferID, StringRef> &bufferFilePaths;
|
|
|
|
/// 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;
|
|
/// 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;
|
|
|
|
/// 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;
|
|
|
|
/// 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;
|
|
};
|
|
|
|
} // namespace ImportVerilog
|
|
} // namespace circt
|
|
|
|
#endif // CONVERSION_IMPORTVERILOG_IMPORTVERILOGINTERNALS_H
|