10#include "slang/ast/SFormat.h"
14using namespace ImportVerilog;
16using moore::IntFormat;
17using moore::IntPadding;
18using moore::RealFormat;
19using slang::ast::SFormat::FormatOptions;
22struct FormatStringParser {
26 ArrayRef<const slang::ast::Expression *> arguments;
31 IntFormat defaultFormat;
34 SmallVector<Value> fragments;
36 FormatStringParser(
Context &context,
37 ArrayRef<const slang::ast::Expression *> arguments,
38 Location loc, IntFormat defaultFormat)
39 : context(context), builder(context.builder), arguments(arguments),
40 loc(loc), defaultFormat(defaultFormat) {}
43 FailureOr<Value> parse(
bool appendNewline) {
44 while (!arguments.empty()) {
45 const auto &arg = *arguments[0];
46 arguments = arguments.drop_front();
47 if (arg.kind == slang::ast::ExpressionKind::EmptyArgument)
50 if (
auto *
lit = arg.as_if<slang::ast::StringLiteral>()) {
51 if (failed(parseFormat(
lit->getValue())))
54 if (failed(emitDefault(arg)))
65 if (fragments.empty())
67 if (fragments.size() == 1)
69 return moore::FormatConcatOp::create(builder, loc, fragments).getResult();
74 LogicalResult parseFormat(StringRef format) {
75 bool anyFailure =
false;
76 auto onText = [&](
auto text) {
81 auto onArg = [&](
auto specifier,
auto offset,
auto len,
82 const auto &options) {
85 if (failed(emitArgument(specifier, format.substr(offset, len), options)))
88 auto onError = [&](
auto,
auto,
auto,
auto) {
89 assert(
false &&
"Slang should have already reported all errors");
91 slang::ast::SFormat::parse(format, onText, onArg, onError);
92 return failure(anyFailure);
96 void emitLiteral(StringRef literal) {
97 fragments.push_back(moore::FormatLiteralOp::create(builder, loc, literal));
102 LogicalResult emitArgument(
char specifier, StringRef fullSpecifier,
103 const FormatOptions &options) {
104 auto specifierLower = std::tolower(specifier);
108 if (specifierLower ==
'm') {
109 bool useEscapes = std::isupper(specifier);
111 moore::FormatHierPathOp::create(builder, loc, useEscapes));
116 if (specifierLower ==
'l') {
127 assert(!arguments.empty() &&
"Slang guarantees correct arg count");
128 const auto &arg = *arguments[0];
129 arguments = arguments.drop_front();
133 switch (specifierLower) {
135 return emitInteger(arg, options, IntFormat::Binary);
137 return emitInteger(arg, options, IntFormat::Octal);
139 return emitInteger(arg, options, IntFormat::Decimal);
142 return emitInteger(arg, options,
143 std::isupper(specifier) ? IntFormat::HexUpper
144 : IntFormat::HexLower);
147 return emitReal(arg, options, RealFormat::Exponential);
149 return emitReal(arg, options, RealFormat::General);
151 return emitReal(arg, options, RealFormat::Float);
154 return emitTime(arg, options);
157 return emitString(arg, options);
159 return emitChar(arg, options);
162 return mlir::emitError(loc)
163 <<
"unsupported format specifier `" << fullSpecifier <<
"`";
168 LogicalResult emitInteger(
const slang::ast::Expression &arg,
169 const FormatOptions &options, IntFormat format) {
177 bool isSigned = arg.type->isSigned() && format == IntFormat::Decimal;
188 if (
auto realTy = dyn_cast<moore::RealType>(rVal.getType())) {
189 if (realTy.getWidth() == moore::RealWidth::f32) {
192 intTy = moore::IntType::getInt(context.
getContext(), 129);
193 }
else if (realTy.getWidth() == moore::RealWidth::f64) {
196 intTy = moore::IntType::getInt(context.
getContext(), 1025);
200 val = moore::RealToIntOp::create(builder, loc, intTy, rVal);
210 auto alignment = options.leftJustify ? IntAlign::Left : IntAlign::Right;
212 format == IntFormat::Decimal ? IntPadding::Space : IntPadding::Zero;
213 IntegerAttr widthAttr =
nullptr;
215 widthAttr = builder.getI32IntegerAttr(*options.width);
218 fragments.push_back(moore::FormatIntOp::create(
219 builder, loc, value, format, alignment, padding, widthAttr, isSigned));
223 LogicalResult emitReal(
const slang::ast::Expression &arg,
224 const FormatOptions &options, RealFormat format) {
229 arg, moore::RealType::get(context.
getContext(), moore::RealWidth::f64));
231 IntegerAttr widthAttr =
nullptr;
233 widthAttr = builder.getI32IntegerAttr(*options.width);
236 IntegerAttr precisionAttr =
nullptr;
237 if (options.precision) {
238 if (*options.precision)
239 precisionAttr = builder.getI32IntegerAttr(*options.precision);
242 precisionAttr = builder.getI32IntegerAttr(1);
245 auto alignment = options.leftJustify ? IntAlign::Left : IntAlign::Right;
249 fragments.push_back(moore::FormatRealOp::create(
250 builder, loc, value, format, alignment, widthAttr, precisionAttr));
260 LogicalResult emitTime(
const slang::ast::Expression &arg,
261 const FormatOptions &options) {
264 arg, moore::IntType::getInt(context.
getContext(), 64));
271 width = *options.width;
272 auto alignment = options.leftJustify ? IntAlign::Left : IntAlign::Right;
273 auto padding = options.zeroPad ? IntPadding::Zero : IntPadding::Space;
274 fragments.push_back(moore::FormatIntOp::create(
275 builder, loc, value, IntFormat::Decimal, alignment, padding,
276 builder.getI32IntegerAttr(width)));
280 LogicalResult emitString(
const slang::ast::Expression &arg,
281 const FormatOptions &options) {
287 arg, moore::StringType::get(context.
getContext()));
290 auto alignment = options.leftJustify ? IntAlign::Left : IntAlign::Right;
291 auto padding = options.zeroPad ? IntPadding::Zero : IntPadding::Space;
292 fragments.push_back(moore::FormatStringOp::create(
293 builder, loc, value, builder.getI32IntegerAttr(*options.width),
294 moore::IntAlignAttr::get(context.
getContext(), alignment),
295 moore::IntPaddingAttr::get(context.
getContext(), padding)));
300 if (
auto *
lit = arg.as_if<slang::ast::StringLiteral>()) {
301 emitLiteral(
lit->getValue());
307 arg, builder.getType<moore::FormatStringType>())) {
308 fragments.push_back(value);
313 <<
"expression cannot be formatted as string";
316 LogicalResult emitChar(
const slang::ast::Expression &arg,
317 const FormatOptions &options) {
319 return mlir::emitError(loc)
320 <<
"character format specifier with width not supported";
330 fragments.push_back(moore::FormatCharOp::create(builder, loc, bitValue));
335 LogicalResult emitDefault(
const slang::ast::Expression &expr) {
336 FormatOptions options;
339 if (expr.type->isString())
340 return emitString(expr, options);
341 return emitInteger(expr, options, defaultFormat);
346FailureOr<Value> Context::convertFormatString(
347 std::span<const slang::ast::Expression *const> arguments, Location loc,
348 IntFormat defaultFormat,
bool appendNewline) {
349 FormatStringParser parser(*
this, ArrayRef(arguments.data(), arguments.size()),
351 return parser.parse(appendNewline);
assert(baseType &&"element must be base type")
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
A helper class to facilitate the conversion from a Slang AST to MLIR operations.
const slang::ast::DefinitionSymbol * currentDefinition
The definition symbol of the module body currently being converted.
Value convertRvalueExpression(const slang::ast::Expression &expr, Type requiredType={})
Value convertToSimpleBitVector(Value value)
Helper function to convert a value to its simple bit vector representation, if it has one.
MLIRContext * getContext()
Return the MLIR context.
Location convertLocation(slang::SourceLocation loc)
Convert a slang SourceLocation into an MLIR Location.