CIRCT 23.0.0git
Loading...
Searching...
No Matches
GenerateDriver.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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 pass generates a self-contained simulation driver for every `arc.model`
10// in the module, so that the model can be run directly through the arcilator
11// JIT without a hand-written driver loop.
12//
13//===----------------------------------------------------------------------===//
14
18#include "mlir/Dialect/Arith/IR/Arith.h"
19#include "mlir/Dialect/Func/IR/FuncOps.h"
20#include "mlir/Dialect/SCF/IR/SCF.h"
21#include "mlir/IR/SymbolTable.h"
22#include "mlir/Pass/Pass.h"
23
24namespace circt {
25namespace arc {
26#define GEN_PASS_DEF_GENERATEDRIVER
27#include "circt/Dialect/Arc/ArcPasses.h.inc"
28} // namespace arc
29} // namespace circt
30
31using namespace mlir;
32using namespace circt;
33using namespace arc;
34
35//===----------------------------------------------------------------------===//
36// Generate Simulation Drivers
37//===----------------------------------------------------------------------===//
38
39namespace {
40struct GenerateDriverPass
41 : public arc::impl::GenerateDriverBase<GenerateDriverPass> {
42 void runOnOperation() override;
43 void generateDriver(ModelOp modelOp, SymbolTable &symbolTable);
44};
45} // namespace
46
47void GenerateDriverPass::runOnOperation() {
48 auto &symbolTable = getAnalysis<SymbolTable>();
49 for (auto modelOp : getOperation().getOps<ModelOp>())
50 generateDriver(modelOp, symbolTable);
51}
52
53/// Generate a `func.func @<model>_main` that runs the given model to
54/// completion.
55void GenerateDriverPass::generateDriver(ModelOp modelOp,
56 SymbolTable &symbolTable) {
57 auto *context = &getContext();
58 auto loc = modelOp.getLoc();
59 auto i64Type = IntegerType::get(context, 64);
60 auto instanceType = SimModelInstanceType::get(
61 context, FlatSymbolRefAttr::get(modelOp.getSymNameAttr()));
62
63 // Create the driver function as a sibling placed before the model. The symbol
64 // table uniquifies the name if it happens to collide.
65 OpBuilder builder(modelOp);
66 auto funcName = builder.getStringAttr(modelOp.getSymName() + "_main");
67 auto funcType = builder.getFunctionType({}, {});
68 auto funcOp = func::FuncOp::create(builder, loc, funcName, funcType);
69 symbolTable.insert(funcOp);
70 builder.setInsertionPointToStart(funcOp.addEntryBlock());
71
72 // Instantiate the model. Its lifetime spans the body region, in which the
73 // model storage is available as the instance block argument.
74 auto instanceOp = SimInstantiateOp::create(builder, loc);
75 func::ReturnOp::create(builder, loc);
76 auto *instanceBlock = builder.createBlock(&instanceOp.getBody());
77 auto instance = instanceBlock->addArgument(instanceType, loc);
78
79 // Loop until no further wakeup is scheduled. The next wakeup slot uses
80 // `UINT64_MAX` to signal that the model has gone quiescent.
81 auto never = arith::ConstantOp::create(builder, loc,
82 builder.getIntegerAttr(i64Type, -1));
83 auto firstWakeup = SimGetNextWakeupOp::create(builder, loc, instance);
84
85 auto whileOp =
86 scf::WhileOp::create(builder, loc, i64Type, ValueRange{firstWakeup});
87
88 // The "before" region tests whether a wakeup is still pending and forwards
89 // the wakeup time into the loop body.
90 auto *beforeBlock = builder.createBlock(&whileOp.getBefore());
91 auto wakeup = beforeBlock->addArgument(i64Type, loc);
92 auto pending = arith::CmpIOp::create(builder, loc, arith::CmpIPredicate::ne,
93 wakeup, never);
94 scf::ConditionOp::create(builder, loc, pending, ValueRange{wakeup});
95
96 // The "after" region advances time to the scheduled wakeup, evaluates the
97 // model, and reads the next wakeup time to feed back into the condition.
98 auto *afterBlock = builder.createBlock(&whileOp.getAfter());
99 auto resumeTime = afterBlock->addArgument(i64Type, loc);
100 SimSetTimeOp::create(builder, loc, instance, resumeTime);
101 SimStepOp::create(builder, loc, instance);
102 auto nextWakeup = SimGetNextWakeupOp::create(builder, loc, instance);
103 scf::YieldOp::create(builder, loc, ValueRange{nextWakeup});
104}
static std::unique_ptr< Context > context
Definition arc.py:1
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.