13using namespace ImportVerilog;
14using moore::IntFormat;
22static bool parseScanFormat(StringRef format,
23 function_ref<
void(StringRef text)> onText,
24 function_ref<
void(
char specifier,
bool suppress,
25 std::optional<uint32_t> maxWidth)>
27 function_ref<
void(StringRef msg)> onError) {
32 while (i < format.size()) {
33 if (format[i] !=
'%') {
39 onText(format.substr(textStart, i - textStart));
42 if (i >= format.size()) {
43 onError(
"unexpected end of format string after '%'");
47 if (format[i] ==
'%') {
55 bool suppress =
false;
56 if (format[i] ==
'*') {
59 if (i >= format.size()) {
60 onError(
"unexpected end of format string after '%*'");
66 std::optional<uint32_t> maxWidth;
67 if (std::isdigit(format[i])) {
69 while (i < format.size() && std::isdigit(format[i]))
70 w = w * 10 + (format[i++] -
'0');
73 onError(
"field width must be at least 1");
78 if (i >= format.size()) {
79 onError(
"unexpected end of format string: missing conversion specifier");
83 char specifier = format[i++];
84 onArg(specifier, suppress, maxWidth);
89 if (textStart < format.size())
90 onText(format.substr(textStart));
95struct ScanStringParser {
100 ArrayRef<const slang::ast::Expression *> destinations;
107 SmallVector<std::tuple<const slang::ast::Expression *, Value, Value>>
110 ScanStringParser(
Context &context, Value initialCursor,
111 ArrayRef<const slang::ast::Expression *> destinations,
113 : context(context), builder(context.builder), destinations(destinations),
114 loc(loc), cursor(initialCursor) {}
118 FailureOr<Context::ScanStringResult> parse(StringRef formatStr) {
119 bool anyFailure =
false;
121 auto onText = [&](StringRef text) {
126 auto onArg = [&](
char specifier,
bool suppress,
127 std::optional<uint32_t> maxWidth) {
130 if (failed(emitScanArg(specifier, suppress, maxWidth)))
134 auto onError = [&](StringRef msg) {
136 mlir::emitError(loc) <<
"scan format string error: " << msg;
141 if (!parseScanFormat(formatStr, onText, onArg, onError) || anyFailure)
144 return Context::ScanStringResult{cursor, std::move(assignments)};
148 void emitLiteral(StringRef text) {
152 moore::ScanLiteralOp::create(builder, loc, cursor, text).getRemaining();
157 static const slang::ast::Expression *
158 unwrapDest(
const slang::ast::Expression *expr) {
159 if (
auto *assign = expr->as_if<slang::ast::AssignmentExpression>())
160 return &assign->left();
166 LogicalResult emitScanArg(
char specifier,
bool suppress,
167 std::optional<uint32_t> maxWidth) {
168 auto specifierLower = std::tolower(specifier);
171 if (specifierLower ==
'm') {
172 cursor = moore::ScanHierPathMatchOp::create(builder, loc, cursor)
177 IntegerAttr maxWidthAttr =
nullptr;
179 maxWidthAttr = builder.getI32IntegerAttr(*maxWidth);
181 const slang::ast::Expression *destExpr =
nullptr;
183 if (destinations.empty())
184 return mlir::emitError(loc)
185 <<
"too few arguments for scan format specifier '%" << specifier
187 destExpr = unwrapDest(destinations.front());
188 destinations = destinations.drop_front();
191 switch (specifierLower) {
194 return emitScanInt(destExpr, suppress, IntFormat::Binary, maxWidthAttr);
196 return emitScanInt(destExpr, suppress, IntFormat::Octal, maxWidthAttr);
198 return emitScanInt(destExpr, suppress, IntFormat::Decimal, maxWidthAttr);
201 return emitScanInt(destExpr, suppress,
202 std::isupper(specifier) ? IntFormat::HexUpper
203 : IntFormat::HexLower,
210 return emitScanReal(destExpr, suppress, maxWidthAttr);
214 return emitScanTime(destExpr, suppress, maxWidthAttr);
218 return emitScanChar(destExpr, suppress);
222 return emitScanStr(destExpr, suppress, maxWidthAttr);
226 return emitScanUnformatted(destExpr, suppress,
false);
228 return emitScanUnformatted(destExpr, suppress,
true);
231 return mlir::emitError(loc)
232 <<
"unknown scan format specifier '%" << specifier <<
"'";
236 LogicalResult emitScanInt(
const slang::ast::Expression *destExpr,
237 bool suppress, IntFormat format,
238 IntegerAttr maxWidth) {
239 auto scanStringTy = moore::ScanStringType::get(builder.getContext());
242 auto op = moore::ScanIntOp::create(builder, loc, TypeRange{scanStringTy},
243 cursor, format, maxWidth);
244 cursor = op.getRemaining();
249 llvm::dyn_cast<moore::IntType>(context.
convertType(*destExpr->type));
251 return mlir::emitError(loc)
252 <<
"destination of integer scan specifier must be an integer";
253 auto mlirIntTy = builder.getIntegerType(mooreIntTy.getWidth());
254 auto matchedTy = moore::IntType::getInt(builder.getContext(), 1);
255 auto op = moore::ScanIntOp::create(builder, loc, scanStringTy, mlirIntTy,
256 matchedTy, cursor, format, maxWidth);
257 cursor = op.getRemaining();
258 auto mooreVal = moore::FromBuiltinIntOp::create(builder, loc, op.getValue())
260 if (mooreIntTy.getDomain() == moore::Domain::FourValued)
261 mooreVal = moore::IntToLogicOp::create(builder, loc, mooreIntTy, mooreVal)
263 assignments.push_back({destExpr, mooreVal, op.getMatched()});
267 LogicalResult emitScanReal(
const slang::ast::Expression *destExpr,
268 bool suppress, IntegerAttr maxWidth) {
269 auto scanStringTy = moore::ScanStringType::get(builder.getContext());
271 auto op = moore::ScanRealOp::create(builder, loc, TypeRange{scanStringTy},
273 cursor = op.getRemaining();
278 llvm::dyn_cast<moore::RealType>(context.
convertType(*destExpr->type));
280 return mlir::emitError(loc)
281 <<
"destination of real scan specifier must be a real";
282 auto matchedTy = moore::IntType::getInt(builder.getContext(), 1);
283 auto op = moore::ScanRealOp::create(
284 builder, loc, TypeRange{scanStringTy, valueTy, matchedTy}, cursor,
286 cursor = op.getRemaining();
287 assignments.push_back({destExpr, op.getValue(), op.getMatched()});
291 LogicalResult emitScanTime(
const slang::ast::Expression *destExpr,
292 bool suppress, IntegerAttr maxWidth) {
293 auto scanStringTy = moore::ScanStringType::get(builder.getContext());
295 auto op = moore::ScanTimeOp::create(builder, loc, TypeRange{scanStringTy},
297 cursor = op.getRemaining();
300 auto valueTy = moore::TimeType::get(builder.getContext());
301 auto matchedTy = moore::IntType::getInt(builder.getContext(), 1);
302 auto op = moore::ScanTimeOp::create(
303 builder, loc, TypeRange{scanStringTy, valueTy, matchedTy}, cursor,
305 cursor = op.getRemaining();
306 assignments.push_back({destExpr, op.getValue(), op.getMatched()});
310 LogicalResult emitScanChar(
const slang::ast::Expression *destExpr,
312 auto scanStringTy = moore::ScanStringType::get(builder.getContext());
314 auto op = moore::ScanCharOp::create(builder, loc, TypeRange{scanStringTy},
316 cursor = op.getRemaining();
320 llvm::dyn_cast<moore::IntType>(context.
convertType(*destExpr->type));
322 return mlir::emitError(loc)
323 <<
"destination of char scan specifier must be an integer";
324 auto mlirIntTy = builder.getIntegerType(mooreIntTy.getWidth());
325 auto matchedTy = moore::IntType::getInt(builder.getContext(), 1);
326 auto op = moore::ScanCharOp::create(
327 builder, loc, TypeRange{scanStringTy, mlirIntTy, matchedTy}, cursor);
328 cursor = op.getRemaining();
329 auto mooreVal = moore::FromBuiltinIntOp::create(builder, loc, op.getValue())
331 if (mooreIntTy.getDomain() == moore::Domain::FourValued)
332 mooreVal = moore::IntToLogicOp::create(builder, loc, mooreIntTy, mooreVal)
334 assignments.push_back({destExpr, mooreVal, op.getMatched()});
338 LogicalResult emitScanStr(
const slang::ast::Expression *destExpr,
339 bool suppress, IntegerAttr maxWidth) {
340 auto scanStringTy = moore::ScanStringType::get(builder.getContext());
342 auto op = moore::ScanStrOp::create(builder, loc, TypeRange{scanStringTy},
344 cursor = op.getRemaining();
347 auto stringTy = moore::StringType::get(builder.getContext());
348 auto matchedTy = moore::IntType::getInt(builder.getContext(), 1);
349 auto op = moore::ScanStrOp::create(
350 builder, loc, TypeRange{scanStringTy, stringTy, matchedTy}, cursor,
352 cursor = op.getRemaining();
353 Value val = op.getValue();
354 auto destTy = context.
convertType(*destExpr->type);
355 if (
auto intTy = llvm::dyn_cast<moore::IntType>(destTy)) {
357 moore::StringToIntOp::create(builder, loc, intTy.getTwoValued(), val)
359 if (intTy.getDomain() == moore::Domain::FourValued)
360 val = moore::IntToLogicOp::create(builder, loc, intTy, val).getResult();
361 }
else if (!llvm::isa<moore::StringType>(destTy)) {
362 return mlir::emitError(loc)
363 <<
"destination of string scan specifier must be a string or "
366 assignments.push_back({destExpr, val, op.getMatched()});
370 LogicalResult emitScanUnformatted(
const slang::ast::Expression *destExpr,
371 bool suppress,
bool fourValue) {
372 auto scanStringTy = moore::ScanStringType::get(builder.getContext());
375 auto op = moore::ScanUnformattedOp::create(
376 builder, loc, TypeRange{scanStringTy}, cursor, fourValue);
377 cursor = op.getRemaining();
381 llvm::dyn_cast<moore::IntType>(context.
convertType(*destExpr->type));
383 return mlir::emitError(loc)
384 <<
"destination of unformatted scan specifier must be an integer";
386 auto mlirIntTy = builder.getIntegerType(mooreIntTy.getWidth());
387 auto matchedTy = moore::IntType::getInt(builder.getContext(), 1);
388 auto op = moore::ScanUnformattedOp::create(
389 builder, loc, TypeRange{scanStringTy, mlirIntTy, matchedTy}, cursor,
391 cursor = op.getRemaining();
392 auto mooreVal = moore::FromBuiltinIntOp::create(builder, loc, op.getValue())
394 if (mooreIntTy.getDomain() == moore::Domain::FourValued)
395 mooreVal = moore::IntToLogicOp::create(builder, loc, mooreIntTy, mooreVal)
397 assignments.push_back({destExpr, mooreVal, op.getMatched()});
404FailureOr<Context::ScanStringResult> Context::convertScanString(
405 StringRef formatStr, Value initialCursor,
406 std::span<const slang::ast::Expression *const> destinations, Location loc) {
407 ScanStringParser parser(*
this, initialCursor,
408 ArrayRef(destinations.data(), destinations.size()),
410 return parser.parse(formatStr);
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
A helper class to facilitate the conversion from a Slang AST to MLIR operations.
Type convertType(const slang::ast::Type &type, LocationAttr loc={})
Convert a slang type into an MLIR type.