Skip to content

Commit 96c8086

Browse files
authored
Move Arcilator pipeline into separate library. (#9213)
Allow re-use of the arcilator library. Split up the large pipeline into finer grained stages and move into its own library. populateHwModuleToArcPipeline is split into: - arcPreprocessingPipeline - arcConversionPipeline - arcOptimizationPipeline - arcStateLoweringPipeline and - arcStateAllocationPipeline
1 parent 45edc51 commit 96c8086

File tree

6 files changed

+309
-92
lines changed

6 files changed

+309
-92
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//===- pipelines.h - Arcilator lowering pipelines -------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file declares the 'arcilator' lowering pipelines.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef TOOLS_ARCILATOR_PIPELINES_H
14+
#define TOOLS_ARCILATOR_PIPELINES_H
15+
16+
#include "mlir/Pass/PassManager.h"
17+
#include "mlir/Pass/PassOptions.h"
18+
#include "llvm/Support/CommandLine.h"
19+
20+
namespace circt {
21+
22+
// Pre-process the input such that it no longer contains any SV dialect ops
23+
// and external modules that are relevant to the arc transformation are
24+
// represented as intrinsic ops.
25+
struct ArcPreprocessingOptions
26+
: mlir::PassPipelineOptions<ArcPreprocessingOptions> {
27+
Option<bool> observePorts{*this, "observe-ports",
28+
llvm::cl::desc("Make all ports observable"),
29+
llvm::cl::init(false)};
30+
31+
Option<bool> observeWires{*this, "observe-wires",
32+
llvm::cl::desc("Make all wires observable"),
33+
llvm::cl::init(false)};
34+
35+
Option<bool> observeNamedValues{
36+
*this, "observe-named-values",
37+
llvm::cl::desc("Make values with `sv.namehint` observable"),
38+
llvm::cl::init(false)};
39+
40+
Option<bool> observeMemories{
41+
*this, "observe-memories",
42+
llvm::cl::desc("Make all memory contents observable"),
43+
llvm::cl::init(false)};
44+
};
45+
void populateArcPreprocessingPipeline(
46+
mlir::OpPassManager &pm, const ArcPreprocessingOptions &options = {});
47+
48+
// Restructure the input from a `hw.module` hierarchy to a collection of arcs.
49+
struct ArcConversionOptions : mlir::PassPipelineOptions<ArcConversionOptions> {
50+
Option<bool> observeRegisters{*this, "observe-registers",
51+
llvm::cl::desc("Make all registers observable"),
52+
llvm::cl::init(false)};
53+
54+
Option<bool> shouldDedup{*this, "dedup", llvm::cl::desc("Deduplicate arcs"),
55+
llvm::cl::init(true)};
56+
};
57+
void populateArcConversionPipeline(mlir::OpPassManager &pm,
58+
const ArcConversionOptions &options = {});
59+
60+
// Perform arc-level optimizations that are not specific to software
61+
// simulation.
62+
struct ArcOptimizationOptions
63+
: mlir::PassPipelineOptions<ArcOptimizationOptions> {
64+
Option<bool> shouldDedup{*this, "dedup", llvm::cl::desc("Deduplicate arcs"),
65+
llvm::cl::init(true)};
66+
67+
Option<bool> shouldDetectEnables{
68+
*this, "detect-enables",
69+
llvm::cl::desc("Infer enable conditions for states to avoid computation"),
70+
llvm::cl::init(true)};
71+
72+
Option<bool> shouldDetectResets{
73+
*this, "detect-resets",
74+
llvm::cl::desc("Infer reset conditions for states to avoid computation"),
75+
llvm::cl::init(false)};
76+
77+
Option<bool> shouldMakeLUTs{
78+
*this, "lookup-tables",
79+
llvm::cl::desc("Optimize arcs into lookup tables"), llvm::cl::init(true)};
80+
};
81+
void populateArcOptimizationPipeline(
82+
mlir::OpPassManager &pm, const ArcOptimizationOptions &options = {});
83+
84+
// Lower stateful arcs into explicit state reads and writes.
85+
struct ArcStateLoweringOptions
86+
: mlir::PassPipelineOptions<ArcStateLoweringOptions> {
87+
Option<bool> shouldInline{*this, "inline", llvm::cl::desc("Inline arcs"),
88+
llvm::cl::init(true)};
89+
};
90+
void populateArcStateLoweringPipeline(
91+
mlir::OpPassManager &pm, const ArcStateLoweringOptions &options = {});
92+
93+
// Allocate states.
94+
struct ArcStateAllocationOptions
95+
: mlir::PassPipelineOptions<ArcStateAllocationOptions> {
96+
Option<unsigned> splitFuncsThreshold{
97+
*this, "split-funcs-threshold",
98+
llvm::cl::desc("Split large MLIR functions that occur above the given "
99+
"size threshold"),
100+
llvm::cl::ValueOptional};
101+
};
102+
void populateArcStateAllocationPipeline(
103+
mlir::OpPassManager &pm, const ArcStateAllocationOptions &options = {});
104+
105+
// Lower the arcs and update functions to LLVM. This pipeline lowers modules to
106+
// LLVM IR.
107+
void populateArcToLLVMPipeline(mlir::OpPassManager &pm);
108+
109+
} // namespace circt
110+
111+
#endif // TOOLS_ARCILATOR_PIPELINE_H

lib/Tools/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
add_subdirectory(arcilator)
12
add_subdirectory(circt-bmc)
23
add_subdirectory(circt-lec)
34

lib/Tools/arcilator/CMakeLists.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
add_circt_library(CIRCTArcilator
2+
pipelines.cpp
3+
4+
ADDITIONAL_HEADER_DIRS
5+
${MLIR_MAIN_INCLUDE_DIR}/circt/Tools/arcilator
6+
7+
LINK_LIBS PUBLIC
8+
CIRCTArc
9+
CIRCTArcToLLVM
10+
CIRCTArcTransforms
11+
CIRCTCombToArith
12+
CIRCTConvertToArcs
13+
CIRCTEmitTransforms
14+
CIRCTExportArc
15+
CIRCTHWTransforms
16+
CIRCTLLHD
17+
CIRCTOMTransforms
18+
CIRCTSeqToSV
19+
CIRCTSeqTransforms
20+
CIRCTSimTransforms
21+
CIRCTSupport
22+
CIRCTTransforms
23+
CIRCTVerif
24+
MLIRLLVMIRTransforms
25+
)

lib/Tools/arcilator/pipelines.cpp

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//===- pipelines.cpp - Arcilator lowering pipelines -----------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file implements the 'arcilator' lowering pipelines.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "circt/Tools/arcilator/pipelines.h"
14+
15+
#include "circt/Conversion/ArcToLLVM.h"
16+
#include "circt/Conversion/CombToArith.h"
17+
#include "circt/Conversion/ConvertToArcs.h"
18+
#include "circt/Conversion/Passes.h"
19+
#include "circt/Conversion/SeqToSV.h"
20+
#include "circt/Dialect/Arc/ArcOps.h"
21+
#include "circt/Dialect/Arc/ArcPasses.h"
22+
#include "circt/Dialect/Emit/EmitPasses.h"
23+
#include "circt/Dialect/HW/HWPasses.h"
24+
#include "circt/Dialect/OM/OMPasses.h"
25+
#include "circt/Dialect/Seq/SeqPasses.h"
26+
#include "circt/Dialect/Sim/SimPasses.h"
27+
#include "circt/Support/Passes.h"
28+
#include "mlir/Transforms/Passes.h"
29+
30+
using namespace mlir;
31+
using namespace circt;
32+
using namespace arc;
33+
34+
void circt::populateArcPreprocessingPipeline(
35+
OpPassManager &pm, const ArcPreprocessingOptions &options) {
36+
pm.addPass(om::createStripOMPass());
37+
pm.addPass(emit::createStripEmitPass());
38+
pm.addPass(createLowerFirMemPass());
39+
pm.addPass(createLowerVerifSimulationsPass());
40+
{
41+
arc::AddTapsOptions opts;
42+
opts.tapPorts = options.observePorts;
43+
opts.tapWires = options.observeWires;
44+
opts.tapNamedValues = options.observeNamedValues;
45+
pm.addPass(arc::createAddTapsPass(opts));
46+
}
47+
pm.addPass(arc::createStripSVPass());
48+
{
49+
arc::InferMemoriesOptions opts;
50+
opts.tapPorts = options.observePorts;
51+
opts.tapMemories = options.observeMemories;
52+
pm.addPass(arc::createInferMemoriesPass(opts));
53+
}
54+
pm.addPass(sim::createLowerDPIFunc());
55+
pm.addPass(createCSEPass());
56+
pm.addPass(arc::createArcCanonicalizerPass());
57+
}
58+
59+
void circt::populateArcConversionPipeline(OpPassManager &pm,
60+
const ArcConversionOptions &options) {
61+
{
62+
ConvertToArcsPassOptions opts;
63+
opts.tapRegisters = options.observeRegisters;
64+
pm.addPass(createConvertToArcsPass(opts));
65+
}
66+
if (options.shouldDedup)
67+
pm.addPass(arc::createDedupPass());
68+
pm.addPass(hw::createFlattenModules());
69+
pm.addPass(createCSEPass());
70+
pm.addPass(arc::createArcCanonicalizerPass());
71+
}
72+
73+
void circt::populateArcOptimizationPipeline(
74+
OpPassManager &pm, const ArcOptimizationOptions &options) {
75+
// Perform arc-level optimizations that are not specific to software
76+
// simulation.
77+
pm.addPass(arc::createSplitLoopsPass());
78+
if (options.shouldDedup)
79+
pm.addPass(arc::createDedupPass());
80+
{
81+
arc::InferStatePropertiesOptions opts;
82+
opts.detectEnables = options.shouldDetectEnables;
83+
opts.detectResets = options.shouldDetectResets;
84+
pm.addPass(arc::createInferStateProperties(opts));
85+
}
86+
pm.addPass(createCSEPass());
87+
pm.addPass(arc::createArcCanonicalizerPass());
88+
pm.addNestedPass<hw::HWModuleOp>(arc::createMergeTaps());
89+
if (options.shouldMakeLUTs)
90+
pm.addPass(arc::createMakeTablesPass());
91+
pm.addPass(createCSEPass());
92+
pm.addPass(arc::createArcCanonicalizerPass());
93+
94+
// Now some arguments may be unused because reset conditions are not passed as
95+
// inputs anymore pm.addPass(arc::createRemoveUnusedArcArgumentsPass());
96+
// Because we replace a lot of StateOp inputs with constants in the enable
97+
// patterns we may be able to sink a lot of them
98+
// TODO: maybe merge RemoveUnusedArcArguments with SinkInputs?
99+
// pm.addPass(arc::createSinkInputsPass());
100+
// pm.addPass(createCSEPass());
101+
// pm.addPass(createSimpleCanonicalizerPass());
102+
// Removing some muxes etc. may lead to additional dedup opportunities
103+
// if (options.shouldDedup)
104+
// pm.addPass(arc::createDedupPass());
105+
}
106+
107+
void circt::populateArcStateLoweringPipeline(
108+
OpPassManager &pm, const ArcStateLoweringOptions &options) {
109+
pm.addPass(arc::createLowerStatePass());
110+
111+
// TODO: LowerClocksToFuncsPass might not properly consider scf.if operations
112+
// (or nested regions in general) and thus errors out when muxes are also
113+
// converted in the hw.module or arc.model
114+
// TODO: InlineArcs seems to not properly handle scf.if operations, thus the
115+
// following is commented out
116+
// pm.addPass(arc::createMuxToControlFlowPass());
117+
if (options.shouldInline)
118+
pm.addPass(arc::createInlineArcsPass());
119+
120+
pm.addPass(arc::createMergeIfsPass());
121+
pm.addPass(createCSEPass());
122+
pm.addPass(arc::createArcCanonicalizerPass());
123+
}
124+
125+
void circt::populateArcStateAllocationPipeline(
126+
OpPassManager &pm, const ArcStateAllocationOptions &options) {
127+
pm.addPass(arc::createLowerArcsToFuncsPass());
128+
pm.nest<arc::ModelOp>().addPass(arc::createAllocateStatePass());
129+
pm.addPass(arc::createLowerClocksToFuncsPass()); // no CSE between state alloc
130+
// and clock func lowering
131+
if (options.splitFuncsThreshold.getNumOccurrences()) {
132+
pm.addPass(arc::createSplitFuncs({options.splitFuncsThreshold}));
133+
}
134+
pm.addPass(createCSEPass());
135+
pm.addPass(arc::createArcCanonicalizerPass());
136+
}
137+
138+
void circt::populateArcToLLVMPipeline(OpPassManager &pm) {
139+
pm.addPass(createLowerArcToLLVMPass());
140+
pm.addPass(createCSEPass());
141+
pm.addPass(arc::createArcCanonicalizerPass());
142+
}

tools/arcilator/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ set(libs
1010
CIRCTArc
1111
CIRCTArcToLLVM
1212
CIRCTArcTransforms
13+
CIRCTArcilator
1314
CIRCTCombToArith
1415
CIRCTConvertToArcs
1516
CIRCTEmitTransforms

0 commit comments

Comments
 (0)