17#include "mlir/Dialect/Func/IR/FuncOps.h"
18#include "mlir/IR/PatternMatch.h"
19#include "mlir/Interfaces/FunctionImplementation.h"
20#include "llvm/ADT/MapVector.h"
27 const Attribute &value,
28 bool isUpperCase,
bool isLeftAligned,
30 std::optional<unsigned> specifierWidth,
31 bool isSigned =
false) {
33 if (
auto intAttr = llvm::dyn_cast_or_null<IntegerAttr>(value)) {
34 SmallVector<char, 32> strBuf;
35 intAttr.getValue().toString(strBuf, radix, isSigned,
false, isUpperCase);
36 unsigned width = intAttr.getType().getIntOrFloatBitWidth();
43 padWidth = (width + 2) / 3;
46 padWidth = (width + 3) / 4;
53 unsigned numSpaces = 0;
54 if (specifierWidth.has_value() &&
55 (specifierWidth.value() >
56 std::max(padWidth,
static_cast<unsigned>(strBuf.size())))) {
58 0U, specifierWidth.value() -
59 std::max(padWidth,
static_cast<unsigned>(strBuf.size())));
62 SmallVector<char, 1> spacePadding(numSpaces,
' ');
64 padWidth = padWidth > strBuf.size() ? padWidth - strBuf.size() : 0;
66 SmallVector<char, 32> padding(padWidth, paddingChar);
68 return StringAttr::get(ctx, Twine(padding) + Twine(strBuf) +
71 return StringAttr::get(ctx, Twine(spacePadding) + Twine(padding) +
79 std::optional<unsigned> fieldWidth,
80 std::optional<unsigned> fracDigits,
81 std::string formatSpecifier) {
82 if (
auto floatAttr = llvm::dyn_cast_or_null<FloatAttr>(value)) {
83 std::string widthString = isLeftAligned ?
"-" :
"";
84 if (fieldWidth.has_value()) {
85 widthString += std::to_string(fieldWidth.value());
87 std::string fmtSpecifier =
"%" + widthString +
"." +
88 std::to_string(fracDigits.value()) +
93 int bufferSize = std::snprintf(
nullptr, 0, fmtSpecifier.c_str(),
94 floatAttr.getValue().convertToDouble());
95 std::string floatFmtBuffer(bufferSize,
'\0');
96 snprintf(floatFmtBuffer.data(), bufferSize + 1, fmtSpecifier.c_str(),
97 floatAttr.getValue().convertToDouble());
98 return StringAttr::get(ctx, floatFmtBuffer);
103ParseResult DPIFuncOp::parse(OpAsmParser &parser, OperationState &result) {
104 auto builder = parser.getBuilder();
106 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
110 if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
114 SmallVector<hw::module_like_impl::PortParse> ports;
120 result.addAttribute(DPIFuncOp::getModuleTypeAttrName(result.name), modType);
124 auto unknownLoc = builder.getUnknownLoc();
125 SmallVector<Attribute> attrs, locs;
126 auto nonEmptyLocsFn = [unknownLoc](Attribute attr) {
127 return attr && cast<Location>(attr) != unknownLoc;
130 for (
auto &port : ports) {
131 attrs.push_back(port.attrs ? port.attrs : builder.getDictionaryAttr({}));
132 locs.push_back(port.sourceLoc ? Location(*port.sourceLoc) : unknownLoc);
135 result.addAttribute(DPIFuncOp::getPerArgumentAttrsAttrName(result.name),
136 builder.getArrayAttr(attrs));
139 if (llvm::any_of(locs, nonEmptyLocsFn))
140 result.addAttribute(DPIFuncOp::getArgumentLocsAttrName(result.name),
141 builder.getArrayAttr(locs));
144 if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
151sim::DPICallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
153 symbolTable.lookupNearestSymbolFrom(*
this, getCalleeAttr());
155 return emitError(
"cannot find function declaration '")
156 << getCallee() <<
"'";
157 if (isa<func::FuncOp, sim::DPIFuncOp>(referencedOp))
159 return emitError(
"callee must be 'sim.dpi.func' or 'func.func' but got '")
160 << referencedOp->getName() <<
"'";
163void DPIFuncOp::print(OpAsmPrinter &p) {
164 DPIFuncOp op = *
this;
167 op->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName())
171 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
172 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
173 p << visibility.getValue() <<
' ';
174 p.printSymbolName(funcName);
176 p, op->getRegion(0), op.getModuleType(),
177 getPerArgumentAttrsAttr()
178 ? ArrayRef<Attribute>(getPerArgumentAttrsAttr().getValue())
179 : ArrayRef<Attribute>{},
180 getArgumentLocs() ? SmallVector<Location>(
181 getArgumentLocs().value().getAsRange<Location>())
182 : ArrayRef<Location>{});
184 mlir::function_interface_impl::printFunctionAttributes(
186 {visibilityAttrName, getModuleTypeAttrName(),
187 getPerArgumentAttrsAttrName(), getArgumentLocsAttrName()});
190OpFoldResult FormatLiteralOp::fold(FoldAdaptor adaptor) {
191 return getLiteralAttr();
194OpFoldResult FormatDecOp::fold(FoldAdaptor adaptor) {
195 if (getValue().getType() == IntegerType::get(getContext(), 0U))
196 return StringAttr::get(getContext(),
"0");
198 if (
auto intAttr = llvm::dyn_cast_or_null<IntegerAttr>(adaptor.getValue())) {
199 SmallVector<char, 16> strBuf;
200 intAttr.getValue().toString(strBuf, 10U, adaptor.getIsSigned());
202 if (adaptor.getSpecifierWidth().has_value()) {
203 padWidth = adaptor.getSpecifierWidth().value();
205 unsigned width = intAttr.getType().getIntOrFloatBitWidth();
206 padWidth = FormatDecOp::getDecimalWidth(width, adaptor.getIsSigned());
209 padWidth = padWidth > strBuf.size() ? padWidth - strBuf.size() : 0;
211 SmallVector<char, 10> padding(padWidth, adaptor.getPaddingChar());
212 if (adaptor.getIsLeftAligned()) {
213 return StringAttr::get(getContext(), Twine(strBuf) + Twine(padding));
215 return StringAttr::get(getContext(), Twine(padding) + Twine(strBuf));
220OpFoldResult FormatHexOp::fold(FoldAdaptor adaptor) {
221 if (getValue().getType() == IntegerType::get(getContext(), 0U))
222 return StringAttr::get(getContext(),
"");
225 getContext(), 16U, adaptor.getValue(), adaptor.getIsHexUppercase(),
226 adaptor.getIsLeftAligned(), adaptor.getPaddingChar(),
227 adaptor.getSpecifierWidth());
230OpFoldResult FormatOctOp::fold(FoldAdaptor adaptor) {
231 if (getValue().getType() == IntegerType::get(getContext(), 0U))
232 return StringAttr::get(getContext(),
"");
235 getContext(), 8U, adaptor.getValue(),
false, adaptor.getIsLeftAligned(),
236 adaptor.getPaddingChar(), adaptor.getSpecifierWidth());
239OpFoldResult FormatBinOp::fold(FoldAdaptor adaptor) {
240 if (getValue().getType() == IntegerType::get(getContext(), 0U))
241 return StringAttr::get(getContext(),
"");
244 getContext(), 2U, adaptor.getValue(),
false, adaptor.getIsLeftAligned(),
245 adaptor.getPaddingChar(), adaptor.getSpecifierWidth());
248OpFoldResult FormatScientificOp::fold(FoldAdaptor adaptor) {
250 getContext(), adaptor.getValue(), adaptor.getIsLeftAligned(),
251 adaptor.getFieldWidth(), adaptor.getFracDigits(),
"e");
254OpFoldResult FormatFloatOp::fold(FoldAdaptor adaptor) {
256 getContext(), adaptor.getValue(), adaptor.getIsLeftAligned(),
257 adaptor.getFieldWidth(), adaptor.getFracDigits(),
"f");
260OpFoldResult FormatGeneralOp::fold(FoldAdaptor adaptor) {
262 getContext(), adaptor.getValue(), adaptor.getIsLeftAligned(),
263 adaptor.getFieldWidth(), adaptor.getFracDigits(),
"g");
266OpFoldResult FormatCharOp::fold(FoldAdaptor adaptor) {
267 auto width = getValue().getType().getIntOrFloatBitWidth();
271 return StringAttr::get(getContext(), Twine(
static_cast<char>(0)));
273 if (
auto intAttr = llvm::dyn_cast_or_null<IntegerAttr>(adaptor.getValue())) {
274 auto intValue = intAttr.getValue().getZExtValue();
275 return StringAttr::get(getContext(), Twine(
static_cast<char>(intValue)));
282 assert(!lits.empty() &&
"No literals to concatenate");
283 if (lits.size() == 1)
284 return StringAttr::get(ctxt, lits.front());
285 SmallString<64> newLit;
286 for (
auto lit : lits)
288 return StringAttr::get(ctxt, newLit);
291OpFoldResult FormatStringConcatOp::fold(FoldAdaptor adaptor) {
292 if (getNumOperands() == 0)
293 return StringAttr::get(getContext(),
"");
294 if (getNumOperands() == 1) {
296 if (getResult() == getOperand(0))
298 return getOperand(0);
302 SmallVector<StringRef> lits;
303 for (
auto attr : adaptor.getInputs()) {
304 auto lit = dyn_cast_or_null<StringAttr>(attr);
312LogicalResult FormatStringConcatOp::getFlattenedInputs(
313 llvm::SmallVectorImpl<Value> &flatOperands) {
314 llvm::SmallMapVector<FormatStringConcatOp, unsigned, 4> concatStack;
315 bool isCyclic =
false;
319 concatStack.insert({*
this, 0});
320 while (!concatStack.empty()) {
321 auto &top = concatStack.back();
322 auto currentConcat = top.first;
323 unsigned operandIndex = top.second;
326 while (operandIndex < currentConcat.getNumOperands()) {
327 auto currentOperand = currentConcat.getOperand(operandIndex);
329 if (
auto nextConcat =
330 currentOperand.getDefiningOp<FormatStringConcatOp>()) {
332 if (!concatStack.contains(nextConcat)) {
335 top.second = operandIndex + 1;
336 concatStack.insert({nextConcat, 0});
343 flatOperands.push_back(currentOperand);
348 if (operandIndex >= currentConcat.getNumOperands())
349 concatStack.pop_back();
352 return success(!isCyclic);
355LogicalResult FormatStringConcatOp::verify() {
356 if (llvm::any_of(getOperands(),
357 [&](Value operand) {
return operand == getResult(); }))
358 return emitOpError(
"is infinitely recursive.");
362LogicalResult FormatStringConcatOp::canonicalize(FormatStringConcatOp op,
363 PatternRewriter &rewriter) {
365 auto fmtStrType = FormatStringType::get(op.getContext());
368 bool hasBeenFlattened =
false;
369 SmallVector<Value, 0> flatOperands;
372 flatOperands.reserve(op.getNumOperands() + 4);
373 auto isAcyclic = op.getFlattenedInputs(flatOperands);
375 if (failed(isAcyclic)) {
378 op.emitWarning(
"Cyclic concatenation detected.");
382 hasBeenFlattened =
true;
385 if (!hasBeenFlattened && op.getNumOperands() < 2)
390 SmallVector<StringRef> litSequence;
391 SmallVector<Value> newOperands;
392 newOperands.reserve(op.getNumOperands());
393 FormatLiteralOp prevLitOp;
395 auto oldOperands = hasBeenFlattened ? flatOperands : op.getOperands();
396 for (
auto operand : oldOperands) {
397 if (
auto litOp = operand.getDefiningOp<FormatLiteralOp>()) {
398 if (!litOp.getLiteral().empty()) {
400 litSequence.push_back(litOp.getLiteral());
403 if (!litSequence.empty()) {
404 if (litSequence.size() > 1) {
406 auto newLit = rewriter.createOrFold<FormatLiteralOp>(
407 op.getLoc(), fmtStrType,
409 newOperands.push_back(newLit);
412 newOperands.push_back(prevLitOp.getResult());
416 newOperands.push_back(operand);
421 if (!litSequence.empty()) {
422 if (litSequence.size() > 1) {
424 auto newLit = rewriter.createOrFold<FormatLiteralOp>(
425 op.getLoc(), fmtStrType,
427 newOperands.push_back(newLit);
430 newOperands.push_back(prevLitOp.getResult());
434 if (!hasBeenFlattened && newOperands.size() == op.getNumOperands())
437 if (newOperands.empty())
438 rewriter.replaceOpWithNewOp<FormatLiteralOp>(op, fmtStrType,
439 rewriter.getStringAttr(
""));
440 else if (newOperands.size() == 1)
441 rewriter.replaceOp(op, newOperands);
443 rewriter.modifyOpInPlace(op, [&]() { op->setOperands(newOperands); });
448LogicalResult PrintFormattedOp::canonicalize(PrintFormattedOp op,
449 PatternRewriter &rewriter) {
451 if (
auto cstCond = op.getCondition().getDefiningOp<
hw::ConstantOp>()) {
452 if (cstCond.getValue().isZero()) {
453 rewriter.eraseOp(op);
460LogicalResult PrintFormattedProcOp::verify() {
462 auto *parentOp = getOperation()->getParentOp();
465 return emitOpError(
"must be within a procedural region.");
467 if (isa_and_nonnull<hw::HWDialect>(parentOp->getDialect())) {
468 if (!isa<hw::TriggeredOp>(parentOp))
469 return emitOpError(
"must be within a procedural region.");
473 if (isa_and_nonnull<sv::SVDialect>(parentOp->getDialect())) {
475 return emitOpError(
"must be within a procedural region.");
483LogicalResult PrintFormattedProcOp::canonicalize(PrintFormattedProcOp op,
484 PatternRewriter &rewriter) {
486 if (
auto litInput = op.getInput().getDefiningOp<FormatLiteralOp>()) {
487 if (litInput.getLiteral().empty()) {
488 rewriter.eraseOp(op);
500#define GET_OP_CLASSES
501#include "circt/Dialect/Sim/Sim.cpp.inc"
assert(baseType &&"element must be base type")
static StringAttr formatFloatsBySpecifier(MLIRContext *ctx, Attribute value, bool isLeftAligned, std::optional< unsigned > fieldWidth, std::optional< unsigned > fracDigits, std::string formatSpecifier)
static StringAttr formatIntegersByRadix(MLIRContext *ctx, unsigned radix, const Attribute &value, bool isUpperCase, bool isLeftAligned, char paddingChar, std::optional< unsigned > specifierWidth, bool isSigned=false)
static StringAttr concatLiterals(MLIRContext *ctxt, ArrayRef< StringRef > lits)
Signals that an operations regions are procedural.
ParseResult parseModuleSignature(OpAsmParser &parser, SmallVectorImpl< PortParse > &args, TypeAttr &modType)
New Style parsing.
void printModuleSignatureNew(OpAsmPrinter &p, Region &body, hw::ModuleType modType, ArrayRef< Attribute > portAttrs, ArrayRef< Location > locAttrs)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.