mirror of https://github.com/llvm/circt.git
[ImportVerilog] Allow enum variants in expressions (#7339)
Add support for enum variants in expressions. Until now, ImportVerilog would emit a "unknown name" diagnostic when an enum variant is used in an expression. This is due to the lowering of named value expressions simply checking whether an MLIR value is present in the `valueSymbols` table for the referenced symbol name. This works for variables which create dedicated declarations, but not for enum variants which potentially live outside the current module's scope. Instead, ImportVerilog will now check if the named value is a constant, for example a parameter or an enum variant, and materialize that constant directly as a `moore.constant` op. This will also be able to deal with parameters declared inside of packages, for which the table of value symbols of the current module does not contain any value. (Local parameters inside the module generate a `moore.named_constant` op that is present in the table.)
This commit is contained in:
parent
f15c4a7a4b
commit
846139b8ba
|
@ -61,13 +61,26 @@ struct RvalueExprVisitor {
|
|||
|
||||
// Handle named values, such as references to declared variables.
|
||||
Value visit(const slang::ast::NamedValueExpression &expr) {
|
||||
if (auto value = context.valueSymbols.lookup(&expr.symbol))
|
||||
return isa<moore::NamedConstantOp>(value.getDefiningOp())
|
||||
? value
|
||||
: builder.create<moore::ReadOp>(
|
||||
loc,
|
||||
cast<moore::RefType>(value.getType()).getNestedType(),
|
||||
value);
|
||||
if (auto value = context.valueSymbols.lookup(&expr.symbol)) {
|
||||
if (auto refType = dyn_cast<moore::RefType>(value.getType()))
|
||||
value =
|
||||
builder.create<moore::ReadOp>(loc, refType.getNestedType(), value);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Try to materialize constant values directly.
|
||||
slang::ast::EvalContext evalContext(context.compilation,
|
||||
slang::ast::EvalFlags::CacheResults);
|
||||
auto constant = expr.eval(evalContext);
|
||||
if (constant.isInteger()) {
|
||||
auto type = context.convertType(*expr.type);
|
||||
if (!type)
|
||||
return {};
|
||||
return convertSVInt(constant.integer(), type);
|
||||
}
|
||||
|
||||
// Otherwise some other part of ImportVerilog should have added an MLIR
|
||||
// value for this expression's symbol to the `context.valueSymbols` table.
|
||||
auto d = mlir::emitError(loc, "unknown name `") << expr.symbol.name << "`";
|
||||
d.attachNote(context.convertLocation(expr.symbol.location))
|
||||
<< "no value generated for " << slang::ast::toString(expr.symbol.kind);
|
||||
|
|
|
@ -262,8 +262,8 @@ LogicalResult ImportDriver::importVerilog(ModuleOp module) {
|
|||
mlirContext
|
||||
->loadDialect<moore::MooreDialect, hw::HWDialect, scf::SCFDialect>();
|
||||
auto conversionTimer = ts.nest("Verilog to dialect mapping");
|
||||
Context context(module, driver.sourceManager, bufferFilePaths);
|
||||
if (failed(context.convertCompilation(*compilation)))
|
||||
Context context(*compilation, module, driver.sourceManager, bufferFilePaths);
|
||||
if (failed(context.convertCompilation()))
|
||||
return failure();
|
||||
conversionTimer.stop();
|
||||
|
||||
|
|
|
@ -44,11 +44,11 @@ struct ModuleLowering {
|
|||
/// operations. Keeps track of the destination MLIR module, builders, and
|
||||
/// various worklists and utilities needed for conversion.
|
||||
struct Context {
|
||||
Context(mlir::ModuleOp intoModuleOp,
|
||||
Context(slang::ast::Compilation &compilation, mlir::ModuleOp intoModuleOp,
|
||||
const slang::SourceManager &sourceManager,
|
||||
SmallDenseMap<slang::BufferID, StringRef> &bufferFilePaths)
|
||||
: intoModuleOp(intoModuleOp), sourceManager(sourceManager),
|
||||
bufferFilePaths(bufferFilePaths),
|
||||
: compilation(compilation), intoModuleOp(intoModuleOp),
|
||||
sourceManager(sourceManager), bufferFilePaths(bufferFilePaths),
|
||||
builder(OpBuilder::atBlockEnd(intoModuleOp.getBody())),
|
||||
symbolTable(intoModuleOp) {}
|
||||
Context(const Context &) = delete;
|
||||
|
@ -69,7 +69,7 @@ struct Context {
|
|||
Type convertType(const slang::ast::DeclaredType &type);
|
||||
|
||||
/// Convert hierarchy and structure AST nodes to MLIR ops.
|
||||
LogicalResult convertCompilation(slang::ast::Compilation &compilation);
|
||||
LogicalResult convertCompilation();
|
||||
ModuleLowering *
|
||||
convertModuleHeader(const slang::ast::InstanceBodySymbol *module);
|
||||
LogicalResult convertModuleBody(const slang::ast::InstanceBodySymbol *module);
|
||||
|
@ -86,6 +86,7 @@ struct Context {
|
|||
LogicalResult
|
||||
convertTimingControl(const slang::ast::TimingControl &timingControl);
|
||||
|
||||
slang::ast::Compilation &compilation;
|
||||
mlir::ModuleOp intoModuleOp;
|
||||
const slang::SourceManager &sourceManager;
|
||||
SmallDenseMap<slang::BufferID, StringRef> &bufferFilePaths;
|
||||
|
|
|
@ -518,8 +518,7 @@ struct ModuleVisitor : public BaseVisitor {
|
|||
|
||||
/// Convert an entire Slang compilation to MLIR ops. This is the main entry
|
||||
/// point for the conversion.
|
||||
LogicalResult
|
||||
Context::convertCompilation(slang::ast::Compilation &compilation) {
|
||||
LogicalResult Context::convertCompilation() {
|
||||
const auto &root = compilation.getRoot();
|
||||
|
||||
// Visit all top-level declarations in all compilation units. This does not
|
||||
|
|
|
@ -198,6 +198,13 @@ module Basic;
|
|||
PackageType pkgType0;
|
||||
// CHECK: %pkgType1 = moore.variable : <l42>
|
||||
Package::PackageType pkgType1;
|
||||
|
||||
// CHECK: [[VARIANT_A:%.+]] = moore.constant 0 :
|
||||
// CHECK: %ev1 = moore.variable [[VARIANT_A]]
|
||||
// CHECK: [[VARIANT_B:%.+]] = moore.constant 1 :
|
||||
// CHECK: %ev2 = moore.variable [[VARIANT_B]]
|
||||
MyEnum ev1 = VariantA;
|
||||
MyEnum ev2 = VariantB;
|
||||
endmodule
|
||||
|
||||
// CHECK-LABEL: moore.module @Statements
|
||||
|
|
Loading…
Reference in New Issue