CIRCT 22.0.0git
Loading...
Searching...
No Matches
ESIModule.cpp
Go to the documentation of this file.
1//===- ESIModule.cpp - ESI API nanobind module ----------------------------===//
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#include "CIRCTModules.h"
10
12
13#include "circt-c/Dialect/ESI.h"
14#include "circt-c/Dialect/HW.h"
15#include "mlir-c/Bindings/Python/Interop.h"
16
17#include "mlir/Bindings/Python/NanobindAdaptors.h"
18#include "mlir/CAPI/IR.h"
19#include "mlir/CAPI/Support.h"
20
21#include "llvm/ADT/DenseMap.h"
22#include "llvm/ADT/SmallVector.h"
23
24#include "NanobindUtils.h"
25#include <nanobind/nanobind.h>
26namespace nb = nanobind;
27
28using namespace circt::esi;
29
30//===----------------------------------------------------------------------===//
31// The main entry point into the ESI Assembly API.
32//===----------------------------------------------------------------------===//
33
34/// Container for a Python function that will be called to generate a service.
36public:
37 ServiceGenFunc(nb::object genFunc) : genFunc(std::move(genFunc)) {}
38
39 MlirLogicalResult run(MlirOperation reqOp, MlirOperation declOp,
40 MlirOperation recOp) {
41 nb::gil_scoped_acquire acquire;
42 nb::object rc = genFunc(reqOp, declOp, recOp);
43 return nb::cast<bool>(rc) ? mlirLogicalResultSuccess()
44 : mlirLogicalResultFailure();
45 }
46
47private:
48 nb::object genFunc;
49};
50
51// Mapping from unique identifier to python callback. We use std::string
52// pointers since we also need to allocate memory for the string.
53llvm::DenseMap<std::string *, ServiceGenFunc> serviceGenFuncLookup;
54static MlirLogicalResult serviceGenFunc(MlirOperation reqOp,
55 MlirOperation declOp,
56 MlirOperation recOp, void *userData) {
57 std::string *name = static_cast<std::string *>(userData);
58 auto iter = serviceGenFuncLookup.find(name);
59 if (iter == serviceGenFuncLookup.end())
60 return mlirLogicalResultFailure();
61 return iter->getSecond().run(reqOp, declOp, recOp);
62}
63
64void registerServiceGenerator(std::string name, nb::object genFunc) {
65 std::string *n = new std::string(name);
66 serviceGenFuncLookup.try_emplace(n, ServiceGenFunc(genFunc));
68}
69
71public:
72 PyAppIDIndex(MlirOperation root) { index = circtESIAppIDIndexGet(root); }
73 PyAppIDIndex(const PyAppIDIndex &) = delete;
75
76 MlirAttribute getChildAppIDsOf(MlirOperation op) const {
78 }
79
80 nb::object getAppIDPathAttr(MlirOperation fromMod, MlirAttribute appid,
81 MlirLocation loc) const {
82 MlirAttribute path =
83 circtESIAppIDIndexGetAppIDPath(index, fromMod, appid, loc);
84 if (path.ptr == nullptr)
85 return nb::none();
86 return nb::cast(path);
87 }
88
89private:
91};
92
93using namespace mlir::python::nanobind_adaptors;
94
96 m.doc() = "ESI Python Native Extension";
98
99 // Clean up references when the module is unloaded.
100 auto cleanup = []() { serviceGenFuncLookup.clear(); };
101 m.def("cleanup", cleanup,
102 "Cleanup various references. Must be called before the module is "
103 "unloaded in order to not leak.");
104
105 m.def("registerServiceGenerator", registerServiceGenerator,
106 "Register a service generator for a given service name.",
107 nb::arg("impl_type"), nb::arg("generator"));
108
109 mlir_type_subclass(m, "ChannelType", circtESITypeIsAChannelType)
110 .def_classmethod(
111 "get",
112 [](nb::object cls, MlirType inner, uint32_t signaling = 0,
113 uint64_t dataDelay = 0) {
115 return cls(inner);
116 return cls(circtESIChannelTypeGet(inner, signaling, dataDelay));
117 },
118 nb::arg("cls"), nb::arg("inner"), nb::arg("signaling") = 0,
119 nb::arg("dataDelay") = 0)
120 .def_property_readonly(
121 "inner", [](MlirType self) { return circtESIChannelGetInner(self); })
122 .def_property_readonly(
123 "signaling",
124 [](MlirType self) { return circtESIChannelGetSignaling(self); })
125 .def_property_readonly("data_delay", [](MlirType self) {
126 return circtESIChannelGetDataDelay(self);
127 });
128
129 mlir_type_subclass(m, "AnyType", circtESITypeIsAnAnyType)
130 .def_classmethod(
131 "get",
132 [](nb::object cls, MlirContext ctxt) {
133 return cls(circtESIAnyTypeGet(ctxt));
134 },
135 nb::arg("self"), nb::arg("ctxt") = nullptr);
136
137 mlir_type_subclass(m, "ListType", circtESITypeIsAListType)
138 .def_classmethod(
139 "get",
140 [](nb::object cls, MlirType inner) {
141 return cls(circtESIListTypeGet(inner));
142 },
143 nb::arg("cls"), nb::arg("inner"))
144 .def_property_readonly("element_type", [](MlirType self) {
146 });
147
148 nb::enum_<ChannelDirection>(m, "ChannelDirection")
149 .value("TO", ChannelDirection::to)
150 .value("FROM", ChannelDirection::from);
151 mlir_type_subclass(m, "BundleType", circtESITypeIsABundleType)
152 .def_classmethod(
153 "get",
154 [](nb::object cls, std::vector<nb::tuple> channelTuples,
155 bool resettable, MlirContext ctxt) {
156 llvm::SmallVector<CirctESIBundleTypeBundleChannel, 4> channels(
157 llvm::map_range(channelTuples, [ctxt](nb::tuple t) {
158 std::string name = nb::cast<std::string>(t[0]);
160 mlirIdentifierGet(ctxt, mlirStringRefCreate(
161 name.data(), name.length())),
162 (uint32_t)nb::cast<ChannelDirection>(t[1]),
163 nb::cast<MlirType>(t[2])};
164 }));
165 return cls(circtESIBundleTypeGet(ctxt, channels.size(),
166 channels.data(), resettable));
167 },
168 nb::arg("cls"), nb::arg("channels"), nb::arg("resettable"),
169 nb::arg("ctxt") = nullptr)
170 .def_property_readonly("resettable", &circtESIBundleTypeGetResettable)
171 .def_property_readonly("channels", [](MlirType bundleType) {
172 std::vector<nb::tuple> channels;
173 size_t numChannels = circtESIBundleTypeGetNumChannels(bundleType);
174 for (size_t i = 0; i < numChannels; ++i) {
176 circtESIBundleTypeGetChannel(bundleType, i);
177 MlirStringRef name = mlirIdentifierStr(channel.name);
178 channels.push_back(nb::make_tuple(nb::str(name.data, name.length),
179 (ChannelDirection)channel.direction,
180 channel.channelType));
181 }
182 return channels;
183 });
184
185 mlir_type_subclass(m, "WindowType", circtESITypeIsAWindowType)
186 .def_classmethod(
187 "get",
188 [](nb::object cls, MlirAttribute name, MlirType into,
189 std::vector<MlirType> frames, MlirContext ctxt) {
190 if (!hwTypeIsAStructType(into) &&
191 (!hwTypeIsATypeAliasType(into) ||
193 throw nb::type_error("'into' type must be a hw.StructType");
194
195 // Verify all frames are WindowFrameTypes
196 for (const auto &frame : frames) {
197 if (!circtESITypeIsAWindowFrameType(frame)) {
198 throw nb::type_error("All frames must be WindowFrameTypes");
199 }
200 }
201 return cls(circtESIWindowTypeGet(ctxt, name, into, frames.size(),
202 frames.data()));
203 },
204 nb::arg("cls"), nb::arg("name"), nb::arg("into"), nb::arg("frames"),
205 nb::arg("ctxt") = nullptr)
206 .def_property_readonly("name", &circtESIWindowTypeGetName)
207 .def_property_readonly("into", &circtESIWindowTypeGetInto)
208 .def_property_readonly(
209 "frames",
210 [](MlirType windowType) {
211 std::vector<MlirType> frames;
212 size_t numFrames = circtESIWindowTypeGetNumFrames(windowType);
213 for (size_t i = 0; i < numFrames; ++i)
214 frames.push_back(circtESIWindowTypeGetFrame(windowType, i));
215 return frames;
216 })
217 .def("get_lowered_type", &circtESIWindowTypeGetLoweredType);
218
219 mlir_type_subclass(m, "WindowFrameType", circtESITypeIsAWindowFrameType)
220 .def_classmethod(
221 "get",
222 [](nb::object cls, MlirAttribute name, std::vector<MlirType> members,
223 MlirContext ctxt) {
224 // Verify all members are WindowFieldTypes
225 for (const auto &member : members) {
226 if (!circtESITypeIsAWindowFieldType(member)) {
227 throw nb::type_error("All members must be WindowFieldTypes");
228 }
229 }
230 return cls(circtESIWindowFrameTypeGet(ctxt, name, members.size(),
231 members.data()));
232 },
233 nb::arg("cls"), nb::arg("name"), nb::arg("members"),
234 nb::arg("ctxt") = nullptr)
235 .def_property_readonly("name", &circtESIWindowFrameTypeGetName)
236 .def_property_readonly("members", [](MlirType frameType) {
237 std::vector<MlirType> members;
238 size_t numMembers = circtESIWindowFrameTypeGetNumMembers(frameType);
239 for (size_t i = 0; i < numMembers; ++i)
240 members.push_back(circtESIWindowFrameTypeGetMember(frameType, i));
241 return members;
242 });
243
244 mlir_type_subclass(m, "WindowFieldType", circtESITypeIsAWindowFieldType)
245 .def_classmethod(
246 "get",
247 [](nb::object cls, MlirAttribute fieldName, uint64_t numItems,
248 MlirContext ctxt) {
249 return cls(circtESIWindowFieldTypeGet(ctxt, fieldName, numItems));
250 },
251 nb::arg("cls"), nb::arg("field_name"), nb::arg("num_items") = 0,
252 nb::arg("ctxt") = nullptr)
253 .def_property_readonly("field_name", &circtESIWindowFieldTypeGetFieldName)
254 .def_property_readonly("num_items", &circtESIWindowFieldTypeGetNumItems);
255
256 mlir_attribute_subclass(m, "AppIDAttr", circtESIAttributeIsAnAppIDAttr)
257 .def_classmethod(
258 "get",
259 [](nb::object cls, std::string name, std::optional<uint64_t> index,
260 MlirContext ctxt) {
261 if (index.has_value())
262 return cls(circtESIAppIDAttrGet(ctxt, wrap(name), index.value()));
263 return cls(circtESIAppIDAttrGetNoIdx(ctxt, wrap(name)));
264 },
265 "Create an AppID attribute", nb::arg("cls"), nb::arg("name"),
266 nb::arg("index") = nb::none(), nb::arg("context") = nb::none())
267 .def_property_readonly("name",
268 [](MlirAttribute self) {
269 llvm::StringRef name =
271 return std::string(name.data(), name.size());
272 })
273 .def_property_readonly("index", [](MlirAttribute self) -> nb::object {
274 uint64_t index;
275 if (circtESIAppIDAttrGetIndex(self, &index))
276 return nb::cast(index);
277 return nb::none();
278 });
279
280 mlir_attribute_subclass(m, "AppIDPathAttr",
282 .def_classmethod(
283 "get",
284 [](nb::object cls, MlirAttribute root,
285 std::vector<MlirAttribute> path, MlirContext ctxt) {
286 return cls(
287 circtESIAppIDAttrPathGet(ctxt, root, path.size(), path.data()));
288 },
289 "Create an AppIDPath attribute", nb::arg("cls"), nb::arg("root"),
290 nb::arg("path"), nb::arg("context") = nb::none())
291 .def_property_readonly("root", &circtESIAppIDAttrPathGetRoot)
293 .def("__getitem__", &circtESIAppIDAttrPathGetComponent);
294
295 m.def("check_inner_type_match", &circtESICheckInnerTypeMatch,
296 "Check that two types match, allowing for AnyType in 'expected'.",
297 nb::arg("expected"), nb::arg("actual"));
298
299 nb::class_<PyAppIDIndex>(m, "AppIDIndex")
300 .def(nb::init<MlirOperation>(), nb::arg("root"))
301 .def("get_child_appids_of", &PyAppIDIndex::getChildAppIDsOf,
302 "Return a dictionary of AppIDAttrs to ArrayAttr of InnerRefAttrs "
303 "containing the relative paths to the leaf of the particular "
304 "AppIDAttr. Argument MUST be HWModuleLike.",
305 nb::arg("mod"))
306 .def("get_appid_path", &PyAppIDIndex::getAppIDPathAttr,
307 "Return an array of InnerNameRefAttrs representing the relative "
308 "path to 'appid' from 'fromMod'.",
309 nb::arg("from_mod"), nb::arg("appid"),
310 nb::arg("query_site") = nb::none());
311}
return wrap(CMemoryType::get(unwrap(ctx), baseType, numElements))
static MlirLogicalResult serviceGenFunc(MlirOperation reqOp, MlirOperation declOp, MlirOperation recOp, void *userData)
Definition ESIModule.cpp:54
void registerServiceGenerator(std::string name, nb::object genFunc)
Definition ESIModule.cpp:64
llvm::DenseMap< std::string *, ServiceGenFunc > serviceGenFuncLookup
Definition ESIModule.cpp:53
MLIR_CAPI_EXPORTED MlirType circtESIWindowFrameTypeGet(MlirContext cctxt, MlirAttribute name, size_t numMembers, const MlirType *members)
Definition ESI.cpp:183
MLIR_CAPI_EXPORTED bool circtESITypeIsAWindowType(MlirType type)
Definition ESI.cpp:144
MLIR_CAPI_EXPORTED uint32_t circtESIChannelGetSignaling(MlirType channelType)
Definition ESI.cpp:46
MLIR_CAPI_EXPORTED MlirType circtESIBundleTypeGet(MlirContext, size_t numChannels, const CirctESIBundleTypeBundleChannel *channels, bool resettable)
Definition ESI.cpp:112
MLIR_CAPI_EXPORTED size_t circtESIWindowTypeGetNumFrames(MlirType window)
Definition ESI.cpp:167
MLIR_CAPI_EXPORTED MlirType circtESIWindowTypeGetFrame(MlirType window, size_t idx)
Definition ESI.cpp:171
MLIR_CAPI_EXPORTED bool circtESITypeIsAWindowFrameType(MlirType type)
Definition ESI.cpp:179
MLIR_CAPI_EXPORTED MlirAttribute circtESIWindowFrameTypeGetName(MlirType frame)
Definition ESI.cpp:194
MLIR_CAPI_EXPORTED MlirAttribute circtESIAppIDAttrGet(MlirContext, MlirStringRef name, uint64_t index)
Definition ESI.cpp:232
MLIR_CAPI_EXPORTED bool circtESIBundleTypeGetResettable(MlirType bundle)
Definition ESI.cpp:126
MLIR_CAPI_EXPORTED bool circtESITypeIsAnAnyType(MlirType type)
Definition ESI.cpp:53
MLIR_CAPI_EXPORTED void circtESIRegisterGlobalServiceGenerator(MlirStringRef impl_type, CirctESIServiceGeneratorFunc, void *userData)
Definition ESI.cpp:94
MLIR_CAPI_EXPORTED MlirAttribute circtESIAppIDIndexGetChildAppIDsOf(CirctESIAppIDIndex, MlirOperation)
Definition ESI.cpp:293
MLIR_CAPI_EXPORTED MlirType circtESIChannelGetInner(MlirType channelType)
Definition ESI.cpp:43
MLIR_CAPI_EXPORTED MlirAttribute circtESIWindowFieldTypeGetFieldName(MlirType field)
Definition ESI.cpp:216
MLIR_CAPI_EXPORTED CirctESIBundleTypeBundleChannel circtESIBundleTypeGetChannel(MlirType bundle, size_t idx)
Definition ESI.cpp:132
MLIR_CAPI_EXPORTED void circtESIAppIDIndexFree(CirctESIAppIDIndex)
Free an AppIDIndex.
Definition ESI.cpp:288
MLIR_CAPI_EXPORTED MlirAttribute circtESIAppIDAttrGetNoIdx(MlirContext ctxt, MlirStringRef name)
Definition ESI.cpp:237
MLIR_CAPI_EXPORTED uint64_t circtESIAppIDAttrPathGetNumComponents(MlirAttribute attr)
Definition ESI.cpp:268
MLIR_CAPI_EXPORTED MlirAttribute circtESIAppIDIndexGetAppIDPath(CirctESIAppIDIndex, MlirOperation fromMod, MlirAttribute appid, MlirLocation loc)
Definition ESI.cpp:299
MLIR_CAPI_EXPORTED MlirType circtESIWindowTypeGetLoweredType(MlirType window)
Definition ESI.cpp:175
MLIR_CAPI_EXPORTED MlirStringRef circtESIAppIDAttrGetName(MlirAttribute attr)
Definition ESI.cpp:241
MLIR_CAPI_EXPORTED MlirType circtESIChannelTypeGet(MlirType inner, uint32_t signaling, uint64_t dataDelay)
Definition ESI.cpp:33
MLIR_CAPI_EXPORTED MlirType circtESIWindowFrameTypeGetMember(MlirType frame, size_t idx)
Definition ESI.cpp:202
MLIR_CAPI_EXPORTED bool circtESITypeIsAChannelType(MlirType type)
Definition ESI.cpp:29
MLIR_CAPI_EXPORTED size_t circtESIBundleTypeGetNumChannels(MlirType bundle)
Definition ESI.cpp:129
MLIR_CAPI_EXPORTED MlirType circtESIListTypeGetElementType(MlirType channelType)
Definition ESI.cpp:69
MLIR_CAPI_EXPORTED MlirType circtESIAnyTypeGet(MlirContext)
Definition ESI.cpp:56
MLIR_CAPI_EXPORTED MlirType circtESIWindowTypeGet(MlirContext cctxt, MlirAttribute name, MlirType into, size_t numFrames, const MlirType *frames)
Definition ESI.cpp:148
MLIR_CAPI_EXPORTED MlirAttribute circtESIAppIDAttrPathGetComponent(MlirAttribute attr, uint64_t index)
Definition ESI.cpp:271
MLIR_CAPI_EXPORTED MlirType circtESIWindowTypeGetInto(MlirType window)
Definition ESI.cpp:163
MLIR_CAPI_EXPORTED MlirType circtESIWindowFieldTypeGet(MlirContext cctxt, MlirAttribute fieldName, uint64_t numItems)
Definition ESI.cpp:210
MLIR_CAPI_EXPORTED uint64_t circtESIWindowFieldTypeGetNumItems(MlirType field)
Definition ESI.cpp:220
MLIR_CAPI_EXPORTED uint64_t circtESIChannelGetDataDelay(MlirType channelType)
Definition ESI.cpp:49
MLIR_CAPI_EXPORTED MlirAttribute circtESIAppIDAttrPathGet(MlirContext, MlirAttribute root, intptr_t numElements, MlirAttribute const *elements)
Definition ESI.cpp:256
MLIR_CAPI_EXPORTED bool circtESITypeIsAWindowFieldType(MlirType type)
Definition ESI.cpp:206
MLIR_CAPI_EXPORTED MlirType circtESIListTypeGet(MlirType inner)
Definition ESI.cpp:64
MLIR_CAPI_EXPORTED bool circtESITypeIsABundleType(MlirType type)
Definition ESI.cpp:109
MLIR_CAPI_EXPORTED bool circtESIAppIDAttrGetIndex(MlirAttribute attr, uint64_t *index)
Definition ESI.cpp:244
MLIR_CAPI_EXPORTED size_t circtESIWindowFrameTypeGetNumMembers(MlirType frame)
Definition ESI.cpp:198
MLIR_CAPI_EXPORTED bool circtESICheckInnerTypeMatch(MlirType to, MlirType from)
Definition ESI.cpp:73
MLIR_CAPI_EXPORTED MlirAttribute circtESIAppIDAttrPathGetRoot(MlirAttribute attr)
Definition ESI.cpp:265
MLIR_CAPI_EXPORTED bool circtESIAttributeIsAnAppIDPathAttr(MlirAttribute)
Definition ESI.cpp:252
MLIR_CAPI_EXPORTED MlirAttribute circtESIWindowTypeGetName(MlirType window)
Definition ESI.cpp:159
MLIR_CAPI_EXPORTED CirctESIAppIDIndex circtESIAppIDIndexGet(MlirOperation root)
Create an index of appids through which to do appid lookups efficiently.
Definition ESI.cpp:280
MLIR_CAPI_EXPORTED bool circtESIAttributeIsAnAppIDAttr(MlirAttribute)
Definition ESI.cpp:228
MLIR_CAPI_EXPORTED bool circtESITypeIsAListType(MlirType type)
Definition ESI.cpp:60
MLIR_CAPI_EXPORTED bool hwTypeIsATypeAliasType(MlirType)
If the type is an HW type alias.
Definition HW.cpp:237
MLIR_CAPI_EXPORTED MlirType hwTypeAliasTypeGetInnerType(MlirType typeAlias)
Definition HW.cpp:258
MLIR_CAPI_EXPORTED bool hwTypeIsAStructType(MlirType)
If the type is an HW struct.
Definition HW.cpp:153
static EvaluatorValuePtr unwrap(OMEvaluatorValue c)
Definition OM.cpp:111
PyAppIDIndex(const PyAppIDIndex &)=delete
CirctESIAppIDIndex index
Definition ESIModule.cpp:90
PyAppIDIndex(MlirOperation root)
Definition ESIModule.cpp:72
nb::object getAppIDPathAttr(MlirOperation fromMod, MlirAttribute appid, MlirLocation loc) const
Definition ESIModule.cpp:80
MlirAttribute getChildAppIDsOf(MlirOperation op) const
Definition ESIModule.cpp:76
Container for a Python function that will be called to generate a service.
Definition ESIModule.cpp:35
MlirLogicalResult run(MlirOperation reqOp, MlirOperation declOp, MlirOperation recOp)
Definition ESIModule.cpp:39
nb::object genFunc
Definition ESIModule.cpp:48
ServiceGenFunc(nb::object genFunc)
Definition ESIModule.cpp:37
void registerESIPasses()
void populateDialectESISubmodule(nanobind::module_ &m)
MlirIdentifier name
Definition ESI.h:50