CIRCT 23.0.0git
Loading...
Searching...
No Matches
ModelInfo.cpp
Go to the documentation of this file.
1//===- ModelInfo.cpp - Information about Arc models -----------------------===//
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// Defines and computes information about Arc models.
10//
11//===----------------------------------------------------------------------===//
12
15#include "llvm/Support/JSON.h"
16
17using namespace mlir;
18using namespace circt;
19using namespace arc;
20
21LogicalResult circt::arc::collectStates(Value storage, unsigned offset,
22 SmallVector<StateInfo> &states) {
23 struct StateCollectionJob {
24 mlir::Value::user_iterator nextToProcess;
25 mlir::Value::user_iterator end;
26 unsigned offset;
27
28 StateCollectionJob(Value storage, unsigned offset)
29 : nextToProcess(storage.user_begin()), end(storage.user_end()),
30 offset(offset) {}
31 };
32
33 SmallVector<StateCollectionJob, 4> jobStack{{storage, offset}};
34
35 while (!jobStack.empty()) {
36 StateCollectionJob &job = jobStack.back();
37
38 if (job.nextToProcess == job.end) {
39 jobStack.pop_back();
40 continue;
41 }
42
43 Operation *op = *job.nextToProcess++;
44 unsigned offset = job.offset;
45
46 if (auto substorage = dyn_cast<AllocStorageOp>(op)) {
47 if (!substorage.getOffset().has_value())
48 return substorage.emitOpError(
49 "without allocated offset; run state allocation first");
50 Value substorageOutput = substorage.getOutput();
51 jobStack.emplace_back(substorageOutput, offset + *substorage.getOffset());
52 continue;
53 }
54
55 if (!isa<AllocStateOp, RootInputOp, RootOutputOp, AllocMemoryOp>(op))
56 continue;
57
58 SmallVector<StringAttr> names;
59
60 auto opName = op->getAttrOfType<StringAttr>("name");
61 if (opName && !opName.getValue().empty())
62 names.push_back(opName);
63
64 if (auto nameAttrs = op->getAttrOfType<ArrayAttr>("names"))
65 for (auto attr : nameAttrs)
66 if (auto nameAttr = dyn_cast<StringAttr>(attr))
67 if (!nameAttr.empty())
68 names.push_back(nameAttr);
69
70 if (names.empty())
71 continue;
72
73 auto opOffset = op->getAttrOfType<IntegerAttr>("offset");
74 if (!opOffset)
75 return op->emitOpError(
76 "without allocated offset; run state allocation first");
77
78 StateInfo stateInfo;
79 if (isa<AllocStateOp, RootInputOp, RootOutputOp>(op)) {
80 auto result = op->getResult(0);
81 stateInfo.type = StateInfo::Register;
82 if (isa<RootInputOp>(op))
83 stateInfo.type = StateInfo::Input;
84 else if (isa<RootOutputOp>(op))
85 stateInfo.type = StateInfo::Output;
86 else if (auto alloc = dyn_cast<AllocStateOp>(op)) {
87 if (alloc.getTap())
88 stateInfo.type = StateInfo::Wire;
89 }
90 stateInfo.offset = opOffset.getValue().getZExtValue() + offset;
91 stateInfo.numBits = cast<StateType>(result.getType()).getBitWidth();
92 for (auto name : names) {
93 stateInfo.name = name.getValue();
94 states.push_back(stateInfo);
95 }
96 continue;
97 }
98
99 if (auto memOp = dyn_cast<AllocMemoryOp>(op)) {
100 auto stride = op->getAttrOfType<IntegerAttr>("stride");
101 if (!stride)
102 return op->emitOpError(
103 "without allocated stride; run state allocation first");
104 auto memType = memOp.getType();
105 auto intType = memType.getWordType();
106 stateInfo.type = StateInfo::Memory;
107 stateInfo.offset = opOffset.getValue().getZExtValue() + offset;
108 stateInfo.numBits = intType.getWidth();
109 stateInfo.memoryStride = stride.getValue().getZExtValue();
110 stateInfo.memoryDepth = memType.getNumWords();
111 for (auto name : names) {
112 stateInfo.name = name.getValue();
113 states.push_back(stateInfo);
114 }
115 continue;
116 }
117 }
118
119 return success();
120}
121
122LogicalResult circt::arc::collectModels(mlir::ModuleOp module,
123 SmallVector<ModelInfo> &models) {
124
125 for (auto modelOp : module.getOps<ModelOp>()) {
126 if (!modelOp.getStorageBytes().has_value())
127 return modelOp->emitOpError(
128 "missing `storageBytes` attribute; run state allocation first");
129 auto storageArg = modelOp.getBody().getArgument(0);
130
131 SmallVector<StateInfo> states;
132 if (failed(collectStates(storageArg, 0, states)))
133 return failure();
134 llvm::stable_sort(states,
135 [](auto &a, auto &b) { return a.offset < b.offset; });
136 models.emplace_back(std::string(modelOp.getName()),
137 *modelOp.getStorageBytes(), std::move(states),
138 modelOp.getInitialFnAttr(), modelOp.getFinalFnAttr());
139 }
140
141 return success();
142}
143
144void circt::arc::serializeModelInfoToJson(llvm::raw_ostream &outputStream,
145 ArrayRef<ModelInfo> models) {
146 llvm::json::OStream json(outputStream, 2);
147
148 json.array([&] {
149 for (const ModelInfo &model : models) {
150 json.object([&] {
151 json.attribute("name", model.name);
152 json.attribute("numStateBytes", model.numStateBytes);
153 json.attribute("initialFnSym", !model.initialFnSym
154 ? ""
155 : model.initialFnSym.getValue());
156 json.attribute("finalFnSym",
157 !model.finalFnSym ? "" : model.finalFnSym.getValue());
158 json.attributeArray("states", [&] {
159 for (const auto &state : model.states) {
160 json.object([&] {
161 json.attribute("name", state.name);
162 json.attribute("offset", state.offset);
163 json.attribute("numBits", state.numBits);
164 auto typeStr = [](StateInfo::Type type) {
165 switch (type) {
166 case StateInfo::Input:
167 return "input";
168 case StateInfo::Output:
169 return "output";
170 case StateInfo::Register:
171 return "register";
172 case StateInfo::Memory:
173 return "memory";
174 case StateInfo::Wire:
175 return "wire";
176 }
177 return "";
178 };
179 json.attribute("type", typeStr(state.type));
180 if (state.type == StateInfo::Memory) {
181 json.attribute("stride", state.memoryStride);
182 json.attribute("depth", state.memoryDepth);
183 }
184 });
185 }
186 });
187 });
188 }
189 });
190}
191
193 assert(container->getNumRegions() == 1 && "Expected single region");
194 assert(container->getRegion(0).getBlocks().size() == 1 &&
195 "Expected single body block");
196
197 for (auto modelOp :
198 container->getRegion(0).getBlocks().front().getOps<ModelOp>()) {
199 auto storageArg = modelOp.getBody().getArgument(0);
200
201 SmallVector<StateInfo> states;
202 if (failed(collectStates(storageArg, 0, states))) {
203 assert(false && "Failed to collect model states");
204 continue;
205 }
206 llvm::stable_sort(states,
207 [](auto &a, auto &b) { return a.offset < b.offset; });
208 assert(modelOp.getStorageBytes().has_value() &&
209 "Expected size of storage to be known");
210 infoMap.try_emplace(modelOp, std::string(modelOp.getName()),
211 *modelOp.getStorageBytes(), std::move(states),
212 modelOp.getInitialFnAttr(), modelOp.getFinalFnAttr());
213 }
214}
assert(baseType &&"element must be base type")
static InstancePath empty
Definition arc.py:1
void serializeModelInfoToJson(llvm::raw_ostream &outputStream, llvm::ArrayRef< ModelInfo > models)
Serializes models to outputStream in JSON format.
mlir::LogicalResult collectModels(mlir::ModuleOp module, llvm::SmallVector< ModelInfo > &models)
Collects information about all Arc models in the provided module, and adds it to models.
mlir::LogicalResult collectStates(mlir::Value storage, unsigned offset, llvm::SmallVector< StateInfo > &states)
Collects information about states within the provided Arc model storage storage, assuming default off...
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
ModelInfoAnalysis(Operation *container)
llvm::MapVector< ModelOp, ModelInfo > infoMap
Definition ModelInfo.h:54