Skip to content

[LLHD] Use new combinational process instead of execute regions #8537

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

Open
wants to merge 1 commit into
base: fschuiki/comb-op
Choose a base branch
from
Open
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
6 changes: 1 addition & 5 deletions include/circt/Dialect/LLHD/Transforms/LLHDPasses.td
Original file line number Diff line number Diff line change
Expand Up @@ -161,18 +161,14 @@ def HoistSignalsPass : Pass<"llhd-hoist-signals"> {
}

def LowerProcessesPass : Pass<"llhd-lower-processes", "hw::HWModuleOp"> {
let summary = "Convert combinational LLHD processes to SCF execute regions";
let dependentDialects = [
"mlir::scf::SCFDialect",
];
let summary = "Convert process ops to combinational ops where possible";
}

def DeseqPass : Pass<"llhd-deseq", "hw::HWModuleOp"> {
let summary = "Convert sequential processes to registers";
let dependentDialects = [
"comb::CombDialect",
"hw::HWDialect",
"mlir::scf::SCFDialect",
"seq::SeqDialect",
];
}
Expand Down
1 change: 0 additions & 1 deletion lib/Dialect/LLHD/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,5 @@ add_circt_dialect_library(CIRCTLLHDTransforms
MLIRControlFlowDialect
MLIRFuncDialect
MLIRIR
MLIRSCFDialect
MLIRTransformUtils
)
33 changes: 17 additions & 16 deletions lib/Dialect/LLHD/Transforms/Deseq.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
#include "circt/Dialect/LLHD/Transforms/LLHDPasses.h"
#include "circt/Dialect/Seq/SeqOps.h"
#include "mlir/Analysis/Liveness.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
#include "mlir/Dialect/SCF/IR/SCF.h"
#include "mlir/IR/Dominance.h"
#include "mlir/IR/IRMapping.h"
#include "mlir/IR/Matchers.h"
#include "mlir/Transforms/RegionUtils.h"
#include "llvm/ADT/ScopeExit.h"
Expand Down Expand Up @@ -1008,7 +1009,7 @@ void Deseq::implementRegisters() {
/// the analyzed clock and reset from the given `DriveInfo` and creates the
/// necessary ops outside the process represent the behavior as a register. It
/// also calls `specializeValue` and `specializeProcess` to convert the
/// sequential `llhd.process` into a purely combinational `scf.execute_region`
/// sequential `llhd.process` into a purely combinational `llhd.combinational`
/// that is simplified by assuming that the clock edge occurs.
void Deseq::implementRegister(DriveInfo &drive) {
OpBuilder builder(drive.op);
Expand Down Expand Up @@ -1128,9 +1129,9 @@ void Deseq::implementRegister(DriveInfo &drive) {

/// Specialize a value by assuming the values listed in `fixedValues` are at a
/// constant value in the past and the present. The function is guaranteed to
/// replace results of the process with results of a new combinational
/// `scf.execute_region` op. All other behavior is purely an optimization; the
/// function may not make use of the assignments in `fixedValues` at all.
/// replace results of the process with results of a new combinational op. All
/// other behavior is purely an optimization; the function may not make use of
/// the assignments in `fixedValues` at all.
Value Deseq::specializeValue(Value value, FixedValues fixedValues) {
auto result = dyn_cast<OpResult>(value);
if (!result || result.getOwner() != process)
Expand All @@ -1140,12 +1141,12 @@ Value Deseq::specializeValue(Value value, FixedValues fixedValues) {

/// Specialize the current process by assuming the values listed in
/// `fixedValues` are at a constant value in the past and the present. This
/// function creates a new `scf.execute_region` op with a simplified version
/// of the process where all uses of the values listed in `fixedValues` are
/// replaced with their constant counterpart. Since the clock-dependent
/// behavior of the process has been absorbed into a register, the process can
/// be replaced with a combinational representation that computes the drive
/// value and drive condition under the assumption that the clock edge occurs.
/// function creates a new combinational op with a simplified version of the
/// process where all uses of the values listed in `fixedValues` are replaced
/// with their constant counterpart. Since the clock-dependent behavior of the
/// process has been absorbed into a register, the process can be replaced with
/// a combinational representation that computes the drive value and drive
/// condition under the assumption that the clock edge occurs.
ValueRange Deseq::specializeProcess(FixedValues fixedValues) {
if (auto it = specializedProcesses.find(fixedValues);
it != specializedProcesses.end())
Expand All @@ -1161,13 +1162,13 @@ ValueRange Deseq::specializeProcess(FixedValues fixedValues) {
}
});

// Create an `scf.execute_region` with this process specialized to compute
// Create an `llhd.combinational` op with this process specialized to compute
// the result for the given fixed values. The triggers will be absorbed into
// the register operation that consumes the result of this specialized
// process, such that we can make the process purely combinational.
OpBuilder builder(process);
auto executeOp = builder.create<scf::ExecuteRegionOp>(
process.getLoc(), process.getResultTypes());
auto executeOp = builder.create<CombinationalOp>(process.getLoc(),
process.getResultTypes());

IRMapping mapping;
SmallVector<std::pair<Block *, Block *>> worklist;
Expand Down Expand Up @@ -1222,14 +1223,14 @@ ValueRange Deseq::specializeProcess(FixedValues fixedValues) {
auto [oldBlock, newBlock] = worklist.pop_back_val();
builder.setInsertionPointToEnd(newBlock);
for (auto &oldOp : *oldBlock) {
// Convert `llhd.wait` into `scf.yield`.
// Convert `llhd.wait` into `llhd.yield`.
if (auto waitOp = dyn_cast<WaitOp>(oldOp)) {
if (stopAtWait)
continue;
SmallVector<Value> operands;
for (auto operand : waitOp.getYieldOperands())
operands.push_back(mapping.lookupOrDefault(operand));
builder.create<scf::YieldOp>(waitOp.getLoc(), operands);
builder.create<YieldOp>(waitOp.getLoc(), operands);
continue;
}

Expand Down
9 changes: 4 additions & 5 deletions lib/Dialect/LLHD/Transforms/LowerProcesses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include "circt/Dialect/LLHD/Transforms/LLHDPasses.h"
#include "mlir/Analysis/Liveness.h"
#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
#include "mlir/Dialect/SCF/IR/SCF.h"
#include "mlir/Transforms/RegionUtils.h"
#include "llvm/Support/Debug.h"

Expand Down Expand Up @@ -56,16 +55,16 @@ void Lowering::lower() {

// Replace the process.
OpBuilder builder(processOp);
auto executeOp = builder.create<scf::ExecuteRegionOp>(
processOp.getLoc(), processOp.getResultTypes());
auto executeOp = builder.create<CombinationalOp>(processOp.getLoc(),
processOp.getResultTypes());
executeOp.getRegion().takeBody(processOp.getBody());
processOp.replaceAllUsesWith(executeOp);
processOp.erase();
processOp = {};

// Replace the `llhd.wait` with an `scf.yield`.
// Replace the `llhd.wait` with an `llhd.yield`.
builder.setInsertionPoint(waitOp);
builder.create<scf::YieldOp>(waitOp.getLoc(), waitOp.getYieldOperands());
builder.create<YieldOp>(waitOp.getLoc(), waitOp.getYieldOperands());
waitOp.erase();

// Simplify the execute op body region since disconnecting the control flow
Expand Down
14 changes: 7 additions & 7 deletions test/Dialect/LLHD/Transforms/deseq.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ hw.module @ClockWithEnable(in %clock: i1, in %d: i42, in %en: i1) {
%c0_i42 = hw.constant 0 : i42
%0 = llhd.constant_time <0ns, 1d, 0e>
// CHECK-NOT: llhd.process
// CHECK: [[ER:%.+]]:2 = scf.execute_region -> (i42, i1) {
// CHECK: [[ER:%.+]]:2 = llhd.combinational -> i42, i1 {
// CHECK: cf.cond_br %en, [[BB:\^.+]](%d, %true : i42, i1), [[BB]](%c0_i42, %false : i42, i1)
// CHECK: [[BB]]([[RESULT:%.+]]: i42, [[ENABLE:%.+]]: i1):
// CHECK: scf.yield [[RESULT]], [[ENABLE]] : i42, i1
// CHECK: llhd.yield [[RESULT]], [[ENABLE]] : i42, i1
// CHECK: }
%1, %2 = llhd.process -> i42, i1 {
%true = hw.constant true
Expand All @@ -142,10 +142,10 @@ hw.module @ClockWithEnableAndReset(in %clock: i1, in %reset: i1, in %d: i42, in
%c0_i42 = hw.constant 0 : i42
%0 = llhd.constant_time <0ns, 1d, 0e>
// CHECK-NOT: llhd.process
// CHECK: [[ER:%.+]]:2 = scf.execute_region -> (i42, i1) {
// CHECK: [[ER:%.+]]:2 = llhd.combinational -> i42, i1 {
// CHECK: cf.cond_br %en, [[BB:\^.+]](%d, %true : i42, i1), [[BB]](%c0_i42, %false : i42, i1)
// CHECK: [[BB]]([[RESULT:%.+]]: i42, [[ENABLE:%.+]]: i1):
// CHECK: scf.yield [[RESULT]], [[ENABLE]] : i42, i1
// CHECK: llhd.yield [[RESULT]], [[ENABLE]] : i42, i1
// CHECK: }
%1, %2 = llhd.process -> i42, i1 {
%true = hw.constant true
Expand Down Expand Up @@ -377,7 +377,7 @@ hw.module @ComplexControlFlow(in %clock: i1, in %d: i42) {
%c0_i42 = hw.constant 0 : i42
%0 = llhd.constant_time <0ns, 1d, 0e>
// CHECK-NOT: llhd.process
// CHECK: [[ER:%.+]]:2 = scf.execute_region -> (i42, i1) {
// CHECK: [[ER:%.+]]:2 = llhd.combinational -> i42, i1 {
// CHECK: cf.br ^bb1(%c0_i42, %false : i42, i1)
// CHECK: ^bb1({{%.+}}: i42, {{%.+}}: i1):
// CHECK: cf.br ^bb2
Expand All @@ -392,7 +392,7 @@ hw.module @ComplexControlFlow(in %clock: i1, in %d: i42) {
// CHECK: [[TMP:%.+]] = comb.icmp ult
// CHECK: cf.cond_br [[TMP]], ^bb3({{.+}}), ^bb4([[RESULT]], %true : i42, i1)
// CHECK: ^bb4([[RESULT:%.+]]: i42, [[ENABLE:%.+]]: i1):
// CHECK: scf.yield [[RESULT]], [[ENABLE]] : i42, i1
// CHECK: llhd.yield [[RESULT]], [[ENABLE]] : i42, i1
// CHECK: }
%1, %2 = llhd.process -> i42, i1 {
%true = hw.constant true
Expand Down Expand Up @@ -593,7 +593,7 @@ hw.module @LargeControlFlowRegression(in %clk: i1, in %rstn: i1, in %a: i6, in %
%mem33 = llhd.sig %c0_i15 : i15
%mem34 = llhd.sig %c0_i15 : i15
// CHECK-NOT: llhd.process
// CHECK: [[ER:%.+]]:70 = scf.execute_region ->
// CHECK: [[ER:%.+]]:70 = llhd.combinational ->
%1:70 = llhd.process -> i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1 {
cf.br ^bb1(%clk, %rstn, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false, %c0_i15, %false : i1, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1, i15, i1)
^bb1(%2: i1, %3: i1, %4: i15, %5: i1, %6: i15, %7: i1, %8: i15, %9: i1, %10: i15, %11: i1, %12: i15, %13: i1, %14: i15, %15: i1, %16: i15, %17: i1, %18: i15, %19: i1, %20: i15, %21: i1, %22: i15, %23: i1, %24: i15, %25: i1, %26: i15, %27: i1, %28: i15, %29: i1, %30: i15, %31: i1, %32: i15, %33: i1, %34: i15, %35: i1, %36: i15, %37: i1, %38: i15, %39: i1, %40: i15, %41: i1, %42: i15, %43: i1, %44: i15, %45: i1, %46: i15, %47: i1, %48: i15, %49: i1, %50: i15, %51: i1, %52: i15, %53: i1, %54: i15, %55: i1, %56: i15, %57: i1, %58: i15, %59: i1, %60: i15, %61: i1, %62: i15, %63: i1, %64: i15, %65: i1, %66: i15, %67: i1, %68: i15, %69: i1, %70: i15, %71: i1, %72: i15, %73: i1):
Expand Down
26 changes: 13 additions & 13 deletions test/Dialect/LLHD/Transforms/lower-processes.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

// CHECK-LABEL: @Trivial(
hw.module @Trivial() {
// CHECK: scf.execute_region {
// CHECK: llhd.combinational {
// CHECK-NEXT: cf.br ^bb1
// CHECK-NEXT: ^bb1:
// CHECK-NEXT: scf.yield
// CHECK-NEXT: llhd.yield
// CHECK-NEXT: }
llhd.process {
cf.br ^bb1
Expand All @@ -16,12 +16,12 @@ hw.module @Trivial() {

// CHECK-LABEL: @BlockArgs(
hw.module @BlockArgs(in %a: i42, in %b: i42) {
// CHECK: scf.execute_region {
// CHECK: llhd.combinational {
// CHECK-NEXT: cf.br ^bb1
// CHECK-NEXT: ^bb1:
// CHECK-NEXT: cf.br ^bb2
// CHECK-NEXT: ^bb2:
// CHECK-NEXT: scf.yield
// CHECK-NEXT: llhd.yield
// CHECK-NEXT: }
llhd.process {
cf.br ^bb1
Expand All @@ -38,10 +38,10 @@ hw.module @BlockArgs(in %a: i42, in %b: i42) {

// CHECK-LABEL: @SupportYieldOperands(
hw.module @SupportYieldOperands(in %a: i42) {
// CHECK: scf.execute_region -> i42 {
// CHECK: llhd.combinational -> i42 {
// CHECK-NEXT: cf.br ^bb1
// CHECK-NEXT: ^bb1:
// CHECK-NEXT: scf.yield %a : i42
// CHECK-NEXT: llhd.yield %a : i42
// CHECK-NEXT: }
llhd.process -> i42 {
cf.br ^bb1
Expand All @@ -56,7 +56,7 @@ hw.module @SupportSeparateProbesOfSameValue() {
%a = llhd.sig %c0_i42 : i42
%0 = llhd.prb %a : !hw.inout<i42>
%1 = llhd.prb %a : !hw.inout<i42>
// CHECK: scf.execute_region
// CHECK: llhd.combinational
llhd.process -> i42 {
cf.br ^bb1
^bb1:
Expand All @@ -66,7 +66,7 @@ hw.module @SupportSeparateProbesOfSameValue() {

// CHECK-LABEL: @SupportObservedArrays(
hw.module @SupportObservedArrays(in %a: i42, in %b: i42) {
// CHECK: scf.execute_region
// CHECK: llhd.combinational
%0 = hw.array_create %a, %b : i42
llhd.process {
cf.br ^bb1
Expand All @@ -78,7 +78,7 @@ hw.module @SupportObservedArrays(in %a: i42, in %b: i42) {

// CHECK-LABEL: @SupportObservedStructs(
hw.module @SupportObservedStructs(in %a: i42, in %b: i42) {
// CHECK: scf.execute_region
// CHECK: llhd.combinational
%0 = hw.struct_create (%a, %b) : !hw.struct<a: i42, b: i42>
llhd.process {
cf.br ^bb1
Expand All @@ -90,7 +90,7 @@ hw.module @SupportObservedStructs(in %a: i42, in %b: i42) {

// CHECK-LABEL: @SupportObservedConcats(
hw.module @SupportObservedConcats(in %a: i42, in %b: i42) {
// CHECK: scf.execute_region
// CHECK: llhd.combinational
%0 = comb.concat %a, %b : i42, i42
llhd.process {
cf.br ^bb1
Expand All @@ -102,7 +102,7 @@ hw.module @SupportObservedConcats(in %a: i42, in %b: i42) {

// CHECK-LABEL: @SupportObservedBitcasts(
hw.module @SupportObservedBitcasts(in %a: i42, in %b: i42) {
// CHECK: scf.execute_region
// CHECK: llhd.combinational
%0 = hw.bitcast %a : (i42) -> !hw.array<2xi21>
%1 = hw.bitcast %b : (i42) -> !hw.array<3xi14>
llhd.process {
Expand All @@ -115,12 +115,12 @@ hw.module @SupportObservedBitcasts(in %a: i42, in %b: i42) {

// CHECK-LABEL: @CommonPattern1(
hw.module @CommonPattern1(in %a: i42, in %b: i42, in %c: i1) {
// CHECK: scf.execute_region -> i42 {
// CHECK: llhd.combinational -> i42 {
// CHECK-NEXT: cf.br ^bb1
// CHECK-NEXT: ^bb1:
// CHECK-NEXT: cf.cond_br %c, ^bb2(%a : i42), ^bb2(%b : i42)
// CHECK-NEXT: ^bb2([[ARG:%.+]]: i42):
// CHECK-NEXT: scf.yield [[ARG]] : i42
// CHECK-NEXT: llhd.yield [[ARG]] : i42
// CHECK-NEXT: }
%0 = llhd.process -> i42 {
cf.br ^bb2(%a, %b : i42, i42)
Expand Down