Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Moore] Add the SimplifyProcedures pass. #7161

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/circt/Dialect/Moore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ mlir_tablegen(MooreAttributes.cpp.inc -gen-attrdef-defs
-attrdefs-dialect MooreDialect)
add_public_tablegen_target(CIRCTMooreAttributesIncGen)
add_dependencies(circt-headers CIRCTMooreAttributesIncGen)

set(LLVM_TARGET_DEFINITIONS MoorePasses.td)
mlir_tablegen(MoorePasses.h.inc -gen-pass-decls)
add_public_tablegen_target(CIRCTMooreTransformsIncGen)
31 changes: 31 additions & 0 deletions include/circt/Dialect/Moore/MoorePasses.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//===- Passes.h - Moore pass entry points -----------------------*- C++ -*-===//
//
// 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 header file defines prototypes that expose pass constructors.
//
//===----------------------------------------------------------------------===//

#ifndef CIRCT_DIALECT_MOORE_MOOREPASSES_H
#define CIRCT_DIALECT_MOORE_MOOREPASSES_H

#include "circt/Dialect/Moore/MooreOps.h"
#include "mlir/Pass/Pass.h"

namespace circt {
namespace moore {

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

/// Generate the code for registering passes.
#define GEN_PASS_REGISTRATION
#include "circt/Dialect/Moore/MoorePasses.h.inc"

} // namespace moore
} // namespace circt

#endif // CIRCT_DIALECT_MOORE_MOOREPASSES_H
32 changes: 32 additions & 0 deletions include/circt/Dialect/Moore/MoorePasses.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//===--- Passes.td - Moore pass definition file ------------*- tablegen -*-===//
//
// 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 passes that work on the Moore dialect.
//
//===----------------------------------------------------------------------===//

#ifndef CIRCT_DIALECT_MOORE_MOOREPASSES_TD
#define CIRCT_DIALECT_MOORE_MOOREPASSES_TD

include "mlir/Pass/PassBase.td"

def SimplifyProcedures : Pass<"simplify-procedures", "moore::SVModuleOp"> {
let summary = "Simplify procedures";
let description = [{
Cause we want to introduce mem2reg in the moore dialect to eliminate the
local temporary variables, if the local variabels exist in the procedure
body, it can be promoted by mem2reg. But global/module-level variables
don't be promoted. So this pass is aimed at inserting a local "shadow"
variable in always blocks for every module-level variable that the
process modifies. Then perform mem2reg to eliminate the local "shadow"
variable.
}];
let constructor = "circt::moore::createSimplifyProceduresPass()";
}

#endif // CIRCT_DIALECT_MOORE_MOOREPASSES_TD
2 changes: 2 additions & 0 deletions include/circt/InitAllPasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "circt/Dialect/Ibis/IbisPasses.h"
#include "circt/Dialect/LLHD/Transforms/Passes.h"
#include "circt/Dialect/MSFT/MSFTPasses.h"
#include "circt/Dialect/Moore/MoorePasses.h"
#include "circt/Dialect/OM/OMPasses.h"
#include "circt/Dialect/Pipeline/PipelinePasses.h"
#include "circt/Dialect/SSP/SSPPasses.h"
Expand Down Expand Up @@ -70,6 +71,7 @@ inline void registerAllPasses() {
ssp::registerPasses();
systemc::registerPasses();
verif::registerPasses();
moore::registerPasses();
}

} // namespace circt
Expand Down
2 changes: 2 additions & 0 deletions lib/Dialect/Moore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ add_circt_dialect_library(CIRCTMoore
)

add_dependencies(circt-headers MLIRMooreIncGen)

add_subdirectory(Transforms)
14 changes: 14 additions & 0 deletions lib/Dialect/Moore/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
add_circt_dialect_library(CIRCTMooreTransforms
SimplifyProcedures.cpp


DEPENDS
CIRCTMooreTransformsIncGen

LINK_LIBS PUBLIC
CIRCTMoore
CIRCTSupport
MLIRIR
MLIRPass
MLIRTransformUtils
)
31 changes: 31 additions & 0 deletions lib/Dialect/Moore/Transforms/PassDetail.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//===- PassDetail.h - Morre pass class details ------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Stuff shared between the different Moore passes.
//
//===----------------------------------------------------------------------===//

// clang-tidy seems to expect the absolute path in the header guard on some
// systems, so just disable it.
// NOLINTNEXTLINE(llvm-header-guard)
#ifndef DIALECT_MOORE_TRANSFORMS_PASSDETAIL_H
#define DIALECT_MOORE_TRANSFORMS_PASSDETAIL_H

#include "circt/Dialect/Moore/MoorePasses.h"
#include "mlir/Pass/Pass.h"

namespace circt {
namespace moore {

#define GEN_PASS_CLASSES
#include "circt/Dialect/Moore/MoorePasses.h.inc"

} // namespace moore
} // namespace circt

#endif // DIALECT_MOORE_TRANSFORMS_PASSDETAIL_H
95 changes: 95 additions & 0 deletions lib/Dialect/Moore/Transforms/SimplifyProcedures.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//===- DeleteLocalVar.cpp - Delete local temporary variables --------------===//
//
// 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 SimplifyProcedures pass.
// Use to insert a local "shadow" variable in always blocks for every
// module-level variable that the process modifies.
//
//===----------------------------------------------------------------------===//

#include "PassDetail.h"
#include "circt/Dialect/Moore/MooreOps.h"
#include "circt/Dialect/Moore/MooreTypes.h"
#include "mlir/IR/Builders.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"

using namespace circt;
using namespace moore;

namespace {
struct SimplifyProceduresPass
: public SimplifyProceduresBase<SimplifyProceduresPass> {
void runOnOperation() override;
};
} // namespace

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

void SimplifyProceduresPass::runOnOperation() {
getOperation()->walk([&](ProcedureOp procedureOp) {
mlir::OpBuilder builder(&getContext());

// Use to collect blocking assignments that have been replaced by a "shadow"
// variable.
DenseSet<Operation *> assignOps;
for (auto &nestedOp : procedureOp) {
// Only create a "shadow" varaible for the global variable used by other
// operations in the procedure body.
if (isa<ReadOp>(nestedOp) &&
isa<SVModuleOp>(
nestedOp.getOperand(0).getDefiningOp()->getParentOp())) {
// Collect the users of the global variable that is mentioned above.
DenseSet<Operation *> users;
for (auto *user : nestedOp.getOperand(0).getUsers())
if (!users.contains(user))
users.insert(user);

auto varOp = cast<VariableOp>(nestedOp.getOperand(0).getDefiningOp());
auto varName = builder.getStringAttr("local_" + varOp.getName());
auto resultType = varOp.getResult().getType();
builder.setInsertionPointToStart(procedureOp.getBody());
auto readOp = builder.create<ReadOp>(
nestedOp.getLoc(), cast<RefType>(resultType).getNestedType(),
varOp.getResult());
auto newVarOp = builder.create<VariableOp>(nestedOp.getLoc(),
resultType, varName, readOp);
builder.clearInsertionPoint();

// Replace the users of the global variable with a corresponding
// "shadow" variable.
for (auto *user : users) {
user->replaceUsesOfWith(user->getOperand(0), newVarOp);
if (isa<BlockingAssignOp>(user))
assignOps.insert(user);
}
}

// Ensure the global variable has the correct value. So needing to create
// a blocking assign for the global variable when the "shadow" variable
// has a new value.
for (auto *assignOp : assignOps)
if (auto localVarOp = llvm::dyn_cast_or_null<VariableOp>(
assignOp->getOperand(0).getDefiningOp())) {
auto resultType = localVarOp.getResult().getType();
builder.setInsertionPointAfter(assignOp);
auto readOp = builder.create<ReadOp>(
localVarOp.getLoc(), cast<RefType>(resultType).getNestedType(),
localVarOp.getResult());
builder.create<BlockingAssignOp>(
nestedOp.getLoc(),
localVarOp.getInitial().getDefiningOp()->getOperand(0), readOp);
builder.clearInsertionPoint();
assignOps.erase(assignOp);
}
}
return WalkResult::advance();
});
}
53 changes: 53 additions & 0 deletions test/Dialect/Moore/simplify-procedures.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// RUN: circt-opt --simplify-procedures %s | FileCheck %s

// CHECK-LABEL: moore.module @Foo()
moore.module @Foo() {
%a = moore.variable : <i32>
%x = moore.variable : <i32>
%y = moore.variable : <i32>
%z = moore.variable : <i32>
moore.procedure always_comb {
// CHECK: %0 = moore.read %a : i32
// CHECK: %local_a = moore.variable %0 : <i32>
// CHECK: %1 = moore.constant 1 : i32
%0 = moore.constant 1 : i32
// CHECK: moore.blocking_assign %local_a, %1 : i32
// CHECK: %2 = moore.read %local_a : i32
// CHECK: moore.blocking_assign %a, %2 : i32
moore.blocking_assign %a, %0 : i32
// CHECK: %3 = moore.read %local_a : i32
%1 = moore.read %a : i32
// CHECK: moore.blocking_assign %x, %3 : i32
moore.blocking_assign %x, %1 : i32
// CHECK: %4 = moore.read %local_a : i32
%2 = moore.read %a : i32
// CHECK: %5 = moore.constant 1 : i32
%3 = moore.constant 1 : i32
// CHECK: %6 = moore.add %4, %5 : i32
%4 = moore.add %2, %3 : i32
// CHECK: moore.blocking_assign %local_a, %6 : i32
// CHECK: %7 = moore.read %local_a : i32
// CHECK: moore.blocking_assign %a, %7 : i32
moore.blocking_assign %a, %4 : i32
// CHECK: %8 = moore.read %local_a : i32
%5 = moore.read %a : i32
// CHECK: moore.blocking_assign %y, %8 : i32
moore.blocking_assign %y, %5 : i32
// CHECK: %9 = moore.read %local_a : i32
%6 = moore.read %a : i32
// CHECK: %10 = moore.constant 1 : i32
%7 = moore.constant 1 : i32
// CHECK: %11 = moore.add %9, %10 : i32
%8 = moore.add %6, %7 : i32
// CHECK: moore.blocking_assign %local_a, %11 : i32
// CHECK: %12 = moore.read %local_a : i32
// CHECK: moore.blocking_assign %a, %12 : i32
moore.blocking_assign %a, %8 : i32
// CHECK: %13 = moore.read %local_a : i32
%9 = moore.read %a : i32
// CHECK: moore.blocking_assign %z, %13 : i32
moore.blocking_assign %z, %9 : i32
}
// CHECK: moore.output
moore.output
}
1 change: 1 addition & 0 deletions tools/circt-opt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ target_link_libraries(circt-opt
CIRCTCombToLLVM
CIRCTLLHDTransforms
CIRCTMoore
CIRCTMooreTransforms
CIRCTMooreToCore
CIRCTMSFT
CIRCTMSFTTransforms
Expand Down
Loading