Skip to content

Commit

Permalink
[Moore] Add AssignedVarOp and a graph region for SVModule.
Browse files Browse the repository at this point in the history
  • Loading branch information
hailongSun2000 committed Jul 1, 2024
1 parent d360917 commit 843f558
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 4 deletions.
1 change: 1 addition & 0 deletions include/circt/Dialect/Moore/MooreOps.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "circt/Dialect/HW/HWTypes.h"
#include "circt/Dialect/Moore/MooreDialect.h"
#include "circt/Dialect/Moore/MooreTypes.h"
#include "mlir/IR/RegionKindInterface.h"
#include "mlir/Interfaces/ControlFlowInterfaces.h"
#include "mlir/Interfaces/InferTypeOpInterface.h"
#include "mlir/Interfaces/MemorySlotInterfaces.h"
Expand Down
23 changes: 19 additions & 4 deletions include/circt/Dialect/Moore/MooreOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class ResultIsSingleBitMatchingInputDomain<string result, string input> :

def SVModuleOp : MooreOp<"module", [
IsolatedFromAbove,
RegionKindInterface,
Symbol,
SingleBlockImplicitTerminator<"OutputOp">,
DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmBlockArgumentNames"]>,
Expand All @@ -49,9 +50,7 @@ def SVModuleOp : MooreOp<"module", [
let description = [{
The `moore.module` operation represents a SystemVerilog module, including
its name, port list, and the constituent parts that make up its body. The
module's body is an SSACFG region, since declarations within SystemVerilog
modules generally have to appear before their uses, and dedicated assignment
operators are used to make connections after declarations.
module's body is a graph region.

See IEEE 1800-2017 § 3.3 "Modules" and § 23.2 "Module definitions".
}];
Expand All @@ -68,6 +67,10 @@ def SVModuleOp : MooreOp<"module", [
OutputOp getOutputOp();
/// Return the list of values assigned to output ports.
OperandRange getOutputs();
/// Implement RegionKindInterface.
static RegionKind getRegionKind(unsigned index) {
return RegionKind::Graph;
}
}];
}

Expand Down Expand Up @@ -246,11 +249,23 @@ def NetOp : MooreOp<"net", [
);
let results = (outs Res<RefType, "", [MemAlloc]>:$result);
let assemblyFormat = [{
``custom<ImplicitSSAName>($name) $kind ($assignment^)? attr-dict
`` custom<ImplicitSSAName>($name) $kind ($assignment^)? attr-dict
`:` type($result)
}];
}

def AssignedVarOp : MooreOp<"assigned_variable", [
DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmResultNames"]>,
TypesMatchWith<"input value and variable types match",
"result", "input", "cast<RefType>($_self).getNestedType()">
]> {
let arguments = (ins StrAttr:$name, UnpackedType:$input);
let results = (outs Res<RefType, "", [MemAlloc]>:$result);
let assemblyFormat = [{
`` custom<ImplicitSSAName>($name) $input attr-dict `:` type($result)
}];
}

def ReadOp : MooreOp<"read", [
DeclareOpInterfaceMethods<PromotableMemOpInterface>,
TypesMatchWith<"input and result types match",
Expand Down
1 change: 1 addition & 0 deletions include/circt/Dialect/Moore/MoorePasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace moore {
#define GEN_PASS_DECL
#include "circt/Dialect/Moore/MoorePasses.h.inc"

std::unique_ptr<mlir::Pass> createMergeAssignmentsPass();
std::unique_ptr<mlir::Pass> createSimplifyProceduresPass();
std::unique_ptr<mlir::Pass> createLowerConcatRefPass();

Expand Down
10 changes: 10 additions & 0 deletions include/circt/Dialect/Moore/MoorePasses.td
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@

include "mlir/Pass/PassBase.td"

def MergeAssignments : Pass<"moore-merge-assignments", "moore::SVModuleOp"> {
let summary = "Merge declarations and assignments";
let description = [{
Find easy uses of declaration and assignment and merge them into
assigned_variable. That allows the MooreToCore lowering to look for
assigned_variable to create an hw.wire.
}];
let constructor = "circt::moore::createMergeAssignmentsPass()";
}

def SimplifyProcedures : Pass<"moore-simplify-procedures", "moore::SVModuleOp"> {
let summary = "Simplify procedures";
let description = [{
Expand Down
8 changes: 8 additions & 0 deletions lib/Dialect/Moore/MooreOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,14 @@ void NetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
setNameFn(getResult(), getName());
}

//===----------------------------------------------------------------------===//
// AssignedVarOp
//===----------------------------------------------------------------------===//

void AssignedVarOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
setNameFn(getResult(), getName());
}

//===----------------------------------------------------------------------===//
// ConstantOp
//===----------------------------------------------------------------------===//
Expand Down
1 change: 1 addition & 0 deletions lib/Dialect/Moore/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
add_circt_dialect_library(CIRCTMooreTransforms
LowerConcatRef.cpp
MergeAssignments.cpp
SimplifyProcedures.cpp


Expand Down
79 changes: 79 additions & 0 deletions lib/Dialect/Moore/Transforms/MergeAssignments.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//===- MergeAssignments.cpp - Merge declaration and assignment ------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the MergeAssignments pass.
// Find easy uses of declaration and assignments and merge them into
// assigned_variable. Easy use represents the declaration doesn't be performed
// bit slice. Like bit [127:0] b; assign b = 128'b0;
//
//===----------------------------------------------------------------------===//

#include "circt/Dialect/Moore/MooreOps.h"
#include "circt/Dialect/Moore/MoorePasses.h"
#include "mlir/IR/Dialect.h"
#include "llvm/ADT/TypeSwitch.h"

namespace circt {
namespace moore {
#define GEN_PASS_DEF_MERGEASSIGNMENTS
#include "circt/Dialect/Moore/MoorePasses.h.inc"
} // namespace moore
} // namespace circt

using namespace circt;
using namespace moore;

namespace {
struct MergeAssignmentsPass
: public circt::moore::impl::MergeAssignmentsBase<MergeAssignmentsPass> {
void runOnOperation() override;
};
} // namespace

std::unique_ptr<mlir::Pass> circt::moore::createMergeAssignmentsPass() {
return std::make_unique<MergeAssignmentsPass>();
}

// TODO: The net can be driven multiple times. However, the related rule is
// complicated. So we will implement this in the future.

// Only collect the easy declaration and its value at module level.
static void collectAssignmets(SVModuleOp moduleOp,
DenseMap<Value, Value> &assignments) {
moduleOp->walk([&](Operation *op) {
TypeSwitch<Operation *>(op).Case<ContinuousAssignOp>([&](auto op) {
if (isa<VariableOp, NetOp>(op.getDst().getDefiningOp())) {
if (!assignments.lookup(op.getDst()))
assignments[op.getDst()] = op.getSrc();
else
mlir::emitError(op.getLoc())
<< "Unsupported drive the same wire '"
<< op.getDst().template getDefiningOp<NetOp>().getName()
<< "' two times now";
}
});
});
}

void MergeAssignmentsPass::runOnOperation() {
OpBuilder builder(&getContext());

// Use to collect the easy declaration and its value.
DenseMap<Value, Value> assignments;

collectAssignmets(getOperation(), assignments);
for (auto assignment : assignments) {
auto varName =
assignment.first.getDefiningOp()->getAttrOfType<StringAttr>("name");

builder.setInsertionPointAfterValue(assignment.first);
builder.create<AssignedVarOp>(assignment.first.getLoc(),
assignment.first.getType(), varName,
assignment.second);
}
}
21 changes: 21 additions & 0 deletions test/Dialect/Moore/merge-assignments.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// RUN: circt-opt --moore-merge-assignments %s | FileCheck %s

// CHECK-LABEL: moore.module @Foo()
moore.module @Foo() {
// CHECK: %a = moore.variable : <i32>
// CHECK: %a_0 = moore.assigned_variable name "a" %0 : <i32>
%a = moore.variable : <i32>

// CHECK: %l = moore.net wire : <l1>
// CHECK: %l_1 = moore.assigned_variable name "l" %2 : <l1>
%l = moore.net wire : <l1>

// CHECK: %0 = moore.constant 32 : i32
%0 = moore.constant 32 : i32
moore.assign %a, %0 : i32
%1 = moore.constant true : i1
%2 = moore.conversion %1 : !moore.i1 -> !moore.l1
moore.assign %l, %2 : l1
moore.output
}

1 change: 1 addition & 0 deletions tools/circt-verilog/circt-verilog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ static LogicalResult populateMooreTransforms(mlir::PassManager &pm) {
modulePM.addPass(moore::createLowerConcatRefPass());
modulePM.addPass(moore::createSimplifyProceduresPass());
pm.addPass(mlir::createMem2Reg());
pm.addNestedPass<moore::SVModuleOp>(moore::createMergeAssignmentsPass());
// TODO: like dedup pass.

return success();
Expand Down

0 comments on commit 843f558

Please sign in to comment.