Skip to content

Commit

Permalink
[ExportVerilog][HW] Introduce HWEmittableModuleLike interface and use…
Browse files Browse the repository at this point in the history
… it for Prepare, NFC (#7004)

This changes pre-passes for ExportVerilog to run on HWEmittableModuleLike instead of HWModuleOp. #6977 is going to add a support for SV func op and legalization needed for SV func as well.

HWEmittableModuleLike is a new interface that inherits Emittable+HWModuleLike. I considered to use a trait but we cannot use a trait for pass scheduling so an interface is used.
  • Loading branch information
uenoku committed Jun 6, 2024
1 parent bf24871 commit 927a376
Show file tree
Hide file tree
Showing 16 changed files with 46 additions and 36 deletions.
1 change: 1 addition & 0 deletions include/circt/Conversion/ExportVerilog.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
namespace circt {
namespace hw {
class HWModuleLike;
class HWEmittableModuleLike;
} // namespace hw

std::unique_ptr<mlir::Pass>
Expand Down
4 changes: 2 additions & 2 deletions include/circt/Conversion/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ def HWLowerInstanceChoices : Pass<"hw-lower-instance-choices",
];
}

def PrepareForEmission : Pass<"prepare-for-emission",
"hw::HWModuleOp"> {
def PrepareForEmission : InterfacePass<"prepare-for-emission",
"hw::HWEmittableModuleLike"> {
let summary = "Prepare IR for ExportVerilog";
let description = [{
This pass runs only PrepareForEmission.
Expand Down
9 changes: 0 additions & 9 deletions include/circt/Dialect/Emit/EmitOpInterfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,6 @@
#include "circt/Support/LLVM.h"
#include "mlir/IR/OpDefinition.h"

namespace circt {
namespace emit {

template <typename ConcreteType>
class Emittable : public OpTrait::TraitBase<ConcreteType, Emittable> {};

} // namespace emit
} // namespace circt

#include "circt/Dialect/Emit/EmitOpInterfaces.h.inc"

#endif // CIRCT_DIALECT_EMIT_EMITOPINTERFACES_H
2 changes: 1 addition & 1 deletion include/circt/Dialect/Emit/EmitOpInterfaces.td
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

include "mlir/IR/OpBase.td"

def Emittable : NativeOpTrait<"Emittable"> {
def Emittable : OpInterface<"Emittable", []> {
let cppNamespace = "::circt::emit";
}

Expand Down
1 change: 1 addition & 0 deletions include/circt/Dialect/HW/HWOpInterfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#ifndef CIRCT_DIALECT_HW_HWOPINTERFACES_H
#define CIRCT_DIALECT_HW_HWOPINTERFACES_H

#include "circt/Dialect/Emit/EmitOpInterfaces.h"
#include "circt/Dialect/HW/HWInstanceImplementation.h"
#include "circt/Dialect/HW/HWTypes.h"
#include "circt/Dialect/HW/InnerSymbolTable.h"
Expand Down
10 changes: 10 additions & 0 deletions include/circt/Dialect/HW/HWOpInterfaces.td
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

include "mlir/IR/SymbolInterfaces.td"
include "mlir/IR/OpBase.td"
include "circt/Dialect/Emit/EmitOpInterfaces.td"
include "circt/Support/InstanceGraphInterface.td"

def PortList : OpInterface<"PortList", []> {
Expand Down Expand Up @@ -402,6 +403,15 @@ def HWMutableModuleLike : OpInterface<"HWMutableModuleLike", [HWModuleLike]> {
];
}

def HWEmittableModuleLike : OpInterface<"HWEmittableModuleLike", [HWModuleLike,
Emittable]> {
let cppNamespace = "::circt::hw";
let description = [{
This interface indicates that the module like op is emittable in SV and
requires SV legalization on its body.
}];
}


def HWInstanceLike : OpInterface<"HWInstanceLike", [
InstanceGraphInstanceOpInterface]> {
Expand Down
2 changes: 1 addition & 1 deletion include/circt/Dialect/HW/HWStructure.td
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class HWModuleOpBase<string mnemonic, list<Trait> traits = []> :
def HWModuleOp : HWModuleOpBase<"module",
[IsolatedFromAbove, RegionKindInterface,
SingleBlockImplicitTerminator<"OutputOp">,
Emittable]>{
HWEmittableModuleLike]>{
let summary = "HW Module";
let description = [{
The "hw.module" operation represents a Verilog module, including a given
Expand Down
3 changes: 2 additions & 1 deletion include/circt/Dialect/SV/SVStatements.td
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,8 @@ def FuncOp : SVOp<"func",
[IsolatedFromAbove, Symbol, OpAsmOpInterface, ProceduralRegion,
DeclareOpInterfaceMethods<HWModuleLike>,
DeclareOpInterfaceMethods<PortList>,
FunctionOpInterface, HasParent<"mlir::ModuleOp">]> {
FunctionOpInterface, HasParent<"mlir::ModuleOp">,
HWEmittableModuleLike]> {
let summary = "A SystemVerilog function";
let description = [{
`sv.func` represents SystemVerilog function in IEEE 1800-2017 section 13.4
Expand Down
17 changes: 10 additions & 7 deletions lib/Conversion/ExportVerilog/ExportVerilog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1413,7 +1413,8 @@ StringAttr ExportVerilog::inferStructuralNameForTemporary(Value expr) {

// Module ports carry names!
if (auto blockArg = dyn_cast<BlockArgument>(expr)) {
auto moduleOp = cast<HWModuleOp>(blockArg.getOwner()->getParentOp());
auto moduleOp =
cast<HWEmittableModuleLike>(blockArg.getOwner()->getParentOp());
StringRef name = getPortVerilogName(moduleOp, blockArg.getArgNumber());
result = StringAttr::get(expr.getContext(), name);

Expand Down Expand Up @@ -6311,7 +6312,7 @@ void FileEmitter::emit(emit::FileListOp op) {
void FileEmitter::emitOp(emit::RefOp op) {
StringAttr target = op.getTargetAttr().getAttr();
auto *targetOp = state.symbolCache.getDefinition(target);
assert(targetOp->hasTrait<emit::Emittable>() && "target must be emittable");
assert(isa<emit::Emittable>(targetOp) && "target must be emittable");

TypeSwitch<Operation *>(targetOp)
.Case<hw::HWModuleOp>(
Expand Down Expand Up @@ -6782,8 +6783,9 @@ LogicalResult circt::exportVerilog(ModuleOp module, llvm::raw_ostream &os) {
LoweringOptions options(module);
if (failed(lowerHWInstanceChoices(module)))
return failure();
SmallVector<HWModuleOp> modulesToPrepare;
module.walk([&](HWModuleOp op) { modulesToPrepare.push_back(op); });
SmallVector<HWEmittableModuleLike> modulesToPrepare;
module.walk(
[&](HWEmittableModuleLike op) { modulesToPrepare.push_back(op); });
if (failed(failableParallelForEach(
module->getContext(), modulesToPrepare,
[&](auto op) { return prepareHWModule(op, options); })))
Expand All @@ -6800,7 +6802,7 @@ struct ExportVerilogPass : public ExportVerilogBase<ExportVerilogPass> {
mlir::OpPassManager preparePM("builtin.module");
preparePM.addPass(createLegalizeAnonEnumsPass());
preparePM.addPass(createHWLowerInstanceChoicesPass());
auto &modulePM = preparePM.nest<hw::HWModuleOp>();
auto &modulePM = preparePM.nestAny();
modulePM.addPass(createPrepareForEmissionPass());
if (failed(runPipeline(preparePM, getOperation())))
return signalPassFailure();
Expand Down Expand Up @@ -6959,8 +6961,9 @@ LogicalResult circt::exportSplitVerilog(ModuleOp module, StringRef dirname) {
LoweringOptions options(module);
if (failed(lowerHWInstanceChoices(module)))
return failure();
SmallVector<HWModuleOp> modulesToPrepare;
module.walk([&](HWModuleOp op) { modulesToPrepare.push_back(op); });
SmallVector<HWEmittableModuleLike> modulesToPrepare;
module.walk(
[&](HWEmittableModuleLike op) { modulesToPrepare.push_back(op); });
if (failed(failableParallelForEach(
module->getContext(), modulesToPrepare,
[&](auto op) { return prepareHWModule(op, options); })))
Expand Down
4 changes: 2 additions & 2 deletions lib/Conversion/ExportVerilog/ExportVerilogInternals.h
Original file line number Diff line number Diff line change
Expand Up @@ -452,10 +452,10 @@ LogicalResult lowerHWInstanceChoices(mlir::ModuleOp module);
/// For each module we emit, do a prepass over the structure, pre-lowering and
/// otherwise rewriting operations we don't want to emit.
LogicalResult prepareHWModule(Block &block, const LoweringOptions &options);
LogicalResult prepareHWModule(hw::HWModuleOp module,
LogicalResult prepareHWModule(hw::HWEmittableModuleLike module,
const LoweringOptions &options);

void pruneZeroValuedLogic(hw::HWModuleOp module);
void pruneZeroValuedLogic(hw::HWEmittableModuleLike module);

/// Rewrite module names and interfaces to not conflict with each other or with
/// Verilog keywords.
Expand Down
14 changes: 8 additions & 6 deletions lib/Conversion/ExportVerilog/LegalizeNames.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,18 @@ class GlobalNameResolver {
} // namespace circt

// This function legalizes local names in the given module.
static void legalizeModuleLocalNames(HWModuleOp module,
static void legalizeModuleLocalNames(HWEmittableModuleLike module,
const LoweringOptions &options,
const GlobalNameTable &globalNameTable) {
// A resolver for a local name collison.
NameCollisionResolver nameResolver(options);
globalNameTable.addReservedNames(nameResolver);

// Register names used by parameters.
for (auto param : module.getParameters())
nameResolver.insertUsedName(globalNameTable.getParameterVerilogName(
module, cast<ParamDeclAttr>(param).getName()));
if (auto hwModule = dyn_cast<hw::HWModuleOp>(*module))
for (auto param : hwModule.getParameters())
nameResolver.insertUsedName(globalNameTable.getParameterVerilogName(
module, cast<ParamDeclAttr>(param).getName()));

auto *ctxt = module.getContext();

Expand Down Expand Up @@ -183,7 +184,7 @@ static void legalizeModuleLocalNames(HWModuleOp module,
// Legalize the value names. We first mark existing hw.verilogName attrs as
// being used, and then resolve names of declarations.
module.walk([&](Operation *op) {
if (!isa<HWModuleOp>(op)) {
if (module != op) {
// If there is a hw.verilogName attr, mark names as used.
if (auto name = op->getAttrOfType<StringAttr>(verilogNameAttr)) {
nameResolver.insertUsedName(
Expand Down Expand Up @@ -274,7 +275,8 @@ GlobalNameResolver::GlobalNameResolver(mlir::ModuleOp topLevel,

// Legalize names in HW modules parallelly.
mlir::parallelForEach(
topLevel.getContext(), topLevel.getOps<HWModuleOp>(), [&](auto module) {
topLevel.getContext(), topLevel.getOps<HWEmittableModuleLike>(),
[&](auto module) {
legalizeModuleLocalNames(module, options, globalNameTable);
});

Expand Down
4 changes: 2 additions & 2 deletions lib/Conversion/ExportVerilog/PrepareForEmission.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1247,7 +1247,7 @@ static LogicalResult legalizeHWModule(Block &block,
}

// NOLINTNEXTLINE(misc-no-recursion)
LogicalResult ExportVerilog::prepareHWModule(hw::HWModuleOp module,
LogicalResult ExportVerilog::prepareHWModule(hw::HWEmittableModuleLike module,
const LoweringOptions &options) {
// Zero-valued logic pruning.
pruneZeroValuedLogic(module);
Expand All @@ -1267,7 +1267,7 @@ namespace {
struct PrepareForEmissionPass
: public PrepareForEmissionBase<PrepareForEmissionPass> {
void runOnOperation() override {
HWModuleOp module = getOperation();
auto module = getOperation();
LoweringOptions options(cast<mlir::ModuleOp>(module->getParentOp()));
if (failed(prepareHWModule(module, options)))
signalPassFailure();
Expand Down
6 changes: 3 additions & 3 deletions lib/Conversion/ExportVerilog/PruneZeroValuedLogic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,9 @@ static void addNoI0ResultPruningPattern(ConversionTarget &target,

} // namespace

void ExportVerilog::pruneZeroValuedLogic(hw::HWModuleOp module) {
ConversionTarget target(*module.getContext());
RewritePatternSet patterns(module.getContext());
void ExportVerilog::pruneZeroValuedLogic(HWEmittableModuleLike module) {
ConversionTarget target(*module->getContext());
RewritePatternSet patterns(module->getContext());
PruneTypeConverter typeConverter;

target.addLegalDialect<sv::SVDialect, comb::CombDialect, hw::HWDialect>();
Expand Down
1 change: 1 addition & 0 deletions lib/Conversion/PassDetail.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class EmitDialect;
namespace hw {
class HWDialect;
class HWModuleOp;
class HWEmittableModuleLike;
} // namespace hw

namespace hwarith {
Expand Down
2 changes: 1 addition & 1 deletion lib/Dialect/Emit/EmitOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ LogicalResult RefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
auto *op = symbolTable.lookupNearestSymbolFrom(getOperation(), target);
if (!op)
return emitError("invalid symbol reference: ") << target;
if (!op->hasTrait<emit::Emittable>())
if (!isa<emit::Emittable>(op))
return emitError("does not target an emittable op: ") << target;
return success();
}
Expand Down
2 changes: 1 addition & 1 deletion test/Conversion/ExportVerilog/prepare-for-emission.mlir
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: circt-opt %s -prepare-for-emission --split-input-file -verify-diagnostics | FileCheck %s
// RUN: circt-opt %s --pass-pipeline='builtin.module(any(prepare-for-emission))' --split-input-file -verify-diagnostics | FileCheck %s
// RUN: circt-opt %s -export-verilog -split-input-file

// CHECK: @namehint_variadic
Expand Down

6 comments on commit 927a376

@uenoku
Copy link
Member Author

@uenoku uenoku commented on 927a376 Jun 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Windows CI is failing in LLVM build. Checking...

@uenoku
Copy link
Member Author

@uenoku uenoku commented on 927a376 Jun 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Windows CI failed even when this commit was revered. https://github.com/llvm/circt/actions/runs/9412723468. Hmm....

@seldridge
Copy link
Member

@seldridge seldridge commented on 927a376 Jun 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the runner was bumped in this to 20240603.1.0. I'm seeing reports of this image having issues. See linked issues on: actions/runner-images#9990

See: actions/runner-images#10004

@teqdruid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, I don't see an official response in the bug thread.

@teqdruid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The consensus in the relevant thread is that there's an issue with the installed DLLs such that usage of std::mutex crashes for code compiled with the image when run on the image. mlir-tblgen fits that description, so it's a good assumption that issue is the problem. (I saw one post on the thread which talked about an LLVM compile break, actually, so we're not the only ones to have LLVM build breakage.) There is a workaround (setting the _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR macro) but GH is deploying a fix "later this week".

@seldridge
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the summary, @teqdruid. I'm fine to wait for the upstream runner fix. Is that good with you?

Please sign in to comment.