CIRCT 24.0.0git
Loading...
Searching...
No Matches
SimTypes.cpp
Go to the documentation of this file.
1//===- SimTypes.cpp -------------------------------------------------------===//
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
12#include "mlir/IR/Builders.h"
13#include "mlir/IR/DialectImplementation.h"
14#include "llvm/ADT/DenseSet.h"
15#include "llvm/ADT/TypeSwitch.h"
16
17// Include the generated enum definitions (DPIDirection).
18#include "circt/Dialect/Sim/SimEnums.h.inc"
19
20using namespace circt;
21using namespace sim;
22using namespace mlir;
23
24//===----------------------------------------------------------------------===//
25// DPIDirection helpers
26//===----------------------------------------------------------------------===//
27
28StringRef sim::stringifyDPIDirectionKeyword(DPIDirection dir) {
29 switch (dir) {
30 case DPIDirection::Input:
31 return "in";
32 case DPIDirection::Output:
33 return "out";
34 case DPIDirection::InOut:
35 return "inout";
36 case DPIDirection::Return:
37 return "return";
38 case DPIDirection::Ref:
39 return "ref";
40 }
41 llvm_unreachable("unknown DPIDirection");
42}
43
44std::optional<DPIDirection> sim::parseDPIDirectionKeyword(StringRef keyword) {
45 return llvm::StringSwitch<std::optional<DPIDirection>>(keyword)
46 .Case("in", DPIDirection::Input)
47 .Case("out", DPIDirection::Output)
48 .Case("inout", DPIDirection::InOut)
49 .Case("return", DPIDirection::Return)
50 .Case("ref", DPIDirection::Ref)
51 .Default(std::nullopt);
52}
53
54bool sim::isCallOperandDir(DPIDirection dir) {
55 return dir == DPIDirection::Input || dir == DPIDirection::InOut ||
56 dir == DPIDirection::Ref;
57}
58
59#define GET_TYPEDEF_CLASSES
60#include "circt/Dialect/Sim/SimTypes.cpp.inc"
61
62void SimDialect::registerTypes() {
63 addTypes<
64#define GET_TYPEDEF_LIST
65#include "circt/Dialect/Sim/SimTypes.cpp.inc"
66 >();
67}
68
69//===----------------------------------------------------------------------===//
70// DPIFunctionType storage
71//===----------------------------------------------------------------------===//
72
74 ArrayRef<DPIArgument> dpiArgs)
75 : arguments(dpiArgs) {
76 for (auto [idx, a] : llvm::enumerate(arguments)) {
77 if (a.dir == DPIDirection::Input || a.dir == DPIDirection::InOut ||
78 a.dir == DPIDirection::Ref)
79 inputToAbs.push_back(idx);
80 if (a.dir == DPIDirection::Output || a.dir == DPIDirection::InOut ||
81 a.dir == DPIDirection::Return)
82 resultToAbs.push_back(idx);
83 }
84}
85
87sim::detail::DPIFunctionTypeStorage::construct(TypeStorageAllocator &allocator,
88 const KeyTy &key) {
89 auto *storage = new (allocator.allocate<DPIFunctionTypeStorage>())
91 // Compute and cache the MLIR FunctionType.
92 SmallVector<Type> inputs, results;
93 for (auto &arg : storage->arguments) {
94 if (arg.dir == DPIDirection::Input || arg.dir == DPIDirection::InOut ||
95 arg.dir == DPIDirection::Ref)
96 inputs.push_back(arg.type);
97 if (arg.dir == DPIDirection::Output || arg.dir == DPIDirection::InOut ||
98 arg.dir == DPIDirection::Return)
99 results.push_back(arg.type);
100 }
101 MLIRContext *ctx = nullptr;
102 if (!storage->arguments.empty()) {
103 ctx = storage->arguments[0].type.getContext();
104 assert(ctx && "DPIArgument types must have a valid MLIRContext");
105 }
106 if (ctx)
107 storage->cachedFuncType = FunctionType::get(ctx, inputs, results);
108 return storage;
109}
110
111//===----------------------------------------------------------------------===//
112// DPIFunctionType methods
113//===----------------------------------------------------------------------===//
114
115ArrayRef<DPIArgument> DPIFunctionType::getArguments() const {
116 return getImpl()->getArguments();
117}
118
119size_t DPIFunctionType::getNumArguments() const {
120 return getImpl()->arguments.size();
121}
122
123SmallVector<DPIArgument> DPIFunctionType::getInputArguments() const {
124 SmallVector<DPIArgument> result;
125 for (auto idx : getImpl()->inputToAbs)
126 result.push_back(getImpl()->arguments[idx]);
127 return result;
128}
129
130SmallVector<DPIArgument> DPIFunctionType::getResultArguments() const {
131 SmallVector<DPIArgument> result;
132 for (auto idx : getImpl()->resultToAbs)
133 result.push_back(getImpl()->arguments[idx]);
134 return result;
135}
136
137const DPIArgument *DPIFunctionType::getReturnArgument() const {
138 auto &args = getImpl()->arguments;
139 if (!args.empty() && args.back().dir == DPIDirection::Return)
140 return &args.back();
141 return nullptr;
142}
143
144FunctionType DPIFunctionType::getFunctionType() const {
145 auto cached = getImpl()->getCachedFunctionType();
146 if (cached)
147 return cached;
148 // Empty argument list — context unavailable during storage construction.
149 return FunctionType::get(getContext(), {}, {});
150}
151
152LogicalResult
153DPIFunctionType::verify(function_ref<InFlightDiagnostic()> emitError) const {
154 auto dpiArgs = getArguments();
155 unsigned returnCount = 0;
156 for (auto [i, arg] : llvm::enumerate(dpiArgs)) {
157 if (arg.dir == DPIDirection::Return) {
158 ++returnCount;
159 if (i != dpiArgs.size() - 1)
160 return emitError() << "'return' argument must be the last argument";
161 }
162 }
163 if (returnCount > 1)
164 return emitError() << "must have at most one 'return' argument";
165 return success();
166}
167
168//===----------------------------------------------------------------------===//
169// DPIFunctionType parser/printer
170//===----------------------------------------------------------------------===//
171
172/// Parse: !sim.dpi_functy<input "a" : i32, output "b" : i32>
173Type DPIFunctionType::parse(AsmParser &parser) {
174 SmallVector<DPIArgument> args;
175 if (parser.parseLess())
176 return {};
177
178 // Handle empty argument list.
179 if (succeeded(parser.parseOptionalGreater()))
180 return get(parser.getContext(), args);
181
182 auto parseOneArg = [&]() -> ParseResult {
183 StringRef dirKeyword;
184 if (parser.parseKeyword(&dirKeyword))
185 return failure();
186 auto dir = parseDPIDirectionKeyword(dirKeyword);
187 if (!dir) {
188 parser.emitError(parser.getCurrentLocation(),
189 "expected DPI argument direction keyword");
190 return failure();
191 }
192 std::string name;
193 if (parser.parseString(&name))
194 return failure();
195 Type type;
196 if (parser.parseColonType(type))
197 return failure();
198 args.push_back({StringAttr::get(parser.getContext(), name), type, *dir});
199 return success();
200 };
201
202 if (parser.parseCommaSeparatedList(parseOneArg) || parser.parseGreater())
203 return {};
204 return get(parser.getContext(), args);
205}
206
207/// Print: !sim.dpi_functy<input "a" : i32, output "b" : i32>
208void DPIFunctionType::print(AsmPrinter &printer) const {
209 printer << '<';
210 llvm::interleaveComma(getArguments(), printer, [&](const DPIArgument &arg) {
211 printer << stringifyDPIDirectionKeyword(arg.dir) << ' ';
212 printer << '"' << arg.name.getValue() << '"';
213 printer << " : ";
214 printer.printType(arg.type);
215 });
216 printer << '>';
217}
218
219//===----------------------------------------------------------------------===//
220// VariantType
221//===----------------------------------------------------------------------===//
222
223/// Parse: !sim.variant<a: i32, b: i8>
224Type VariantType::parse(AsmParser &p) {
225 SmallVector<Alternative, 4> alternatives;
226 SmallVector<std::pair<llvm::SMLoc, StringAttr>> duplicates;
227 auto parseResult = parseFieldList(p, alternatives, duplicates);
228 for (auto [loc, name] : duplicates)
229 p.emitError(loc) << "duplicate alternative name '" << name.getValue()
230 << "' in sim.variant type";
231 if (failed(parseResult) || !duplicates.empty())
232 return Type();
233 return get(p.getContext(), alternatives);
234}
235
236/// Print: !sim.variant<a: i32, b: i8>
237void VariantType::print(AsmPrinter &p) const {
238 printFieldList(p, getAlternatives());
239}
240
241LogicalResult VariantType::verify(function_ref<InFlightDiagnostic()> emitError,
242 ArrayRef<Alternative> alternatives) {
243 llvm::SmallDenseSet<StringAttr> nameSet;
244 LogicalResult result = success();
245 nameSet.reserve(alternatives.size());
246 for (const auto &alternative : alternatives)
247 if (!nameSet.insert(alternative.name).second) {
248 result = failure();
249 emitError() << "duplicate alternative name '"
250 << alternative.name.getValue() << "' in sim.variant type";
251 }
252 return result;
253}
254
255std::optional<uint32_t> VariantType::getAlternativeIndex(StringAttr name) {
256 ArrayRef<Alternative> alternatives = getAlternatives();
257 for (size_t idx = 0, numAlternatives = alternatives.size();
258 idx < numAlternatives; ++idx)
259 if (alternatives[idx].name == name)
260 return idx;
261 return {};
262}
263
264std::optional<uint32_t> VariantType::getAlternativeIndex(StringRef name) {
265 return getAlternativeIndex(StringAttr::get(getContext(), name));
266}
267
268VariantType::Alternative VariantType::getAlternative(StringRef name) {
269 if (auto index = getAlternativeIndex(name))
270 return getAlternatives()[*index];
271 return Alternative();
272}
273
274Type VariantType::getAlternativeType(StringRef name) {
275 return getAlternative(name).type;
276}
assert(baseType &&"element must be base type")
false return failure()
Parse an optional keyword or string and set instance into 'result'.
return success()
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition CalyxOps.cpp:56
llvm::StringRef stringifyDPIDirectionKeyword(DPIDirection dir)
Return the keyword string for a DPIDirection (e.g. "in", "return").
Definition SimTypes.cpp:28
std::optional< DPIDirection > parseDPIDirectionKeyword(llvm::StringRef keyword)
Parse a keyword string to a DPIDirection. Returns std::nullopt on failure.
bool isCallOperandDir(DPIDirection dir)
True if an argument with this direction is a call operand (input/inout/ref).
Definition SimTypes.cpp:54
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
ParseResult parseFieldList(AsmParser &p, SmallVectorImpl< FieldInfo > &fields, SmallVectorImpl< std::pair< llvm::SMLoc, StringAttr > > &duplicates)
Parse a list of named fields within <>, e.g.
Definition FieldInfo.cpp:15
void printFieldList(AsmPrinter &p, ArrayRef< FieldInfo > fields)
Print a list of fields within <>, e.g. <foo: i7, bar: i8>.
Definition FieldInfo.cpp:38
Definition sim.py:1
llvm::SmallVector< DPIArgument > arguments
Definition SimTypes.h:75
DPIFunctionTypeStorage(llvm::ArrayRef< DPIArgument > args)
Definition SimTypes.cpp:73
llvm::SmallVector< size_t > inputToAbs
Definition SimTypes.h:76
llvm::SmallVector< size_t > resultToAbs
Definition SimTypes.h:77
static DPIFunctionTypeStorage * construct(mlir::TypeStorageAllocator &allocator, const KeyTy &key)
Definition SimTypes.cpp:87
llvm::ArrayRef< DPIArgument > KeyTy
Definition SimTypes.h:55