14#include "mlir/IR/Diagnostics.h"
15#include "mlir/IR/DialectImplementation.h"
16#include "llvm/ADT/SmallString.h"
17#include "llvm/ADT/StringExtras.h"
18#include "llvm/ADT/TypeSwitch.h"
19#include "llvm/Support/FileSystem.h"
20#include "llvm/Support/Path.h"
34#define GET_ATTRDEF_CLASSES
35#include "circt/Dialect/HW/HWAttributes.cpp.inc"
37void HWDialect::registerAttributes() {
39#define GET_ATTRDEF_LIST
40#include "circt/Dialect/HW/HWAttributes.cpp.inc"
44Attribute HWDialect::parseAttribute(DialectAsmParser &p, Type type)
const {
47 auto parseResult = generatedAttributeParser(p, &attrName, type, attr);
48 if (parseResult.has_value())
52 if (attrName.starts_with(ParamExprAttr::getMnemonic())) {
53 auto string = attrName.drop_front(ParamExprAttr::getMnemonic().size());
54 if (
string.front() ==
'.')
58 p.emitError(p.getNameLoc(),
"Unexpected hw attribute '" + attrName +
"'");
62void HWDialect::printAttribute(Attribute attr, DialectAsmPrinter &p)
const {
63 if (succeeded(generatedAttributePrinter(attr, p)))
65 llvm_unreachable(
"Unexpected attribute");
73 const Twine &filename) {
76 SmallString<128> nativeFilename;
77 llvm::sys::path::native(filename, nativeFilename);
81 if (llvm::sys::path::is_absolute(nativeFilename))
82 return std::string(nativeFilename);
85 SmallString<128> nativeDirectory;
86 llvm::sys::path::native(directory, nativeDirectory);
91 auto separator = llvm::sys::path::get_separator();
92 if (nativeFilename.empty() && !nativeDirectory.ends_with(separator)) {
93 nativeDirectory += separator;
94 return std::string(nativeDirectory);
99 SmallString<128> fullPath;
100 llvm::sys::path::append(fullPath, nativeDirectory, nativeFilename);
101 return std::string(fullPath);
104OutputFileAttr OutputFileAttr::getFromFilename(MLIRContext *context,
105 const Twine &filename,
106 bool excludeFromFileList,
107 bool includeReplicatedOps) {
108 return OutputFileAttr::getFromDirectoryAndFilename(
109 context,
"", filename, excludeFromFileList, includeReplicatedOps);
112OutputFileAttr OutputFileAttr::getFromDirectoryAndFilename(
113 MLIRContext *context,
const Twine &directory,
const Twine &filename,
114 bool excludeFromFileList,
bool includeReplicatedOps) {
116 return OutputFileAttr::get(StringAttr::get(context, canonicalized),
117 BoolAttr::get(context, excludeFromFileList),
118 BoolAttr::get(context, includeReplicatedOps));
121OutputFileAttr OutputFileAttr::getAsDirectory(MLIRContext *context,
122 const Twine &directory,
123 bool excludeFromFileList,
124 bool includeReplicatedOps) {
125 return getFromDirectoryAndFilename(context, directory,
"",
126 excludeFromFileList, includeReplicatedOps);
129bool OutputFileAttr::isDirectory() {
130 return getFilename().getValue().ends_with(llvm::sys::path::get_separator());
133StringRef OutputFileAttr::getDirectory() {
134 auto dir = getFilename().getValue();
135 for (
unsigned i = 0, e = dir.size(); i < e; ++i) {
136 if (dir.ends_with(llvm::sys::path::get_separator()))
138 dir = dir.drop_back();
145Attribute OutputFileAttr::parse(AsmParser &p, Type type) {
147 if (p.parseLess() || p.parseAttribute<StringAttr>(filename))
152 bool excludeFromFileList =
false;
153 bool includeReplicatedOps =
false;
155 if (p.parseOptionalComma())
157 if (!p.parseOptionalKeyword(
"excludeFromFileList"))
158 excludeFromFileList =
true;
159 else if (!p.parseKeyword(
"includeReplicatedOps",
160 "or 'excludeFromFileList'"))
161 includeReplicatedOps =
true;
166 if (p.parseGreater())
169 return OutputFileAttr::getFromFilename(p.getContext(), filename.getValue(),
171 includeReplicatedOps);
174void OutputFileAttr::print(AsmPrinter &p)
const {
175 p <<
"<" << getFilename();
176 if (getExcludeFromFilelist().getValue())
177 p <<
", excludeFromFileList";
178 if (getIncludeReplicatedOps().getValue())
179 p <<
", includeReplicatedOps";
187Attribute EnumFieldAttr::parse(AsmParser &p, Type) {
190 if (p.parseLess() || p.parseKeyword(&field) || p.parseComma() ||
191 p.parseType(type) || p.parseGreater())
193 return EnumFieldAttr::get(p.getEncodedSourceLoc(p.getCurrentLocation()),
194 StringAttr::get(p.getContext(), field), type);
197void EnumFieldAttr::print(AsmPrinter &p)
const {
198 p <<
"<" << getField().getValue() <<
", ";
199 p.printType(getType().getValue());
203EnumFieldAttr EnumFieldAttr::get(Location loc, StringAttr value,
205 if (!hw::isHWEnumType(type))
206 emitError(loc) <<
"expected enum type";
210 if (!enumType.contains(value.getValue())) {
211 emitError(loc) <<
"enum value '" << value.getValue()
212 <<
"' is not a member of enum type " << enumType;
216 return Base::get(value.getContext(), value, TypeAttr::get(type));
223Attribute InnerRefAttr::parse(AsmParser &p, Type type) {
225 if (p.parseLess() || p.parseAttribute<SymbolRefAttr>(attr) ||
228 if (attr.getNestedReferences().size() != 1) {
229 p.emitError(p.getNameLoc(),
230 "inner reference must have exactly one nested reference");
233 return InnerRefAttr::get(attr.getRootReference(), attr.getLeafReference());
238 p.printSymbolName(sym.getValue());
240 p.printSymbolName({});
243void InnerRefAttr::print(AsmPrinter &p)
const {
255Attribute InnerSymPropertiesAttr::parse(AsmParser &parser, Type type) {
257 NamedAttrList dummyList;
259 if (parser.parseLess() || parser.parseSymbolName(name,
"name", dummyList) ||
260 parser.parseComma() || parser.parseInteger(fieldId) ||
264 StringRef visibility;
265 auto loc = parser.getCurrentLocation();
266 if (parser.parseOptionalKeyword(&visibility,
267 {
"public",
"private",
"nested"})) {
268 parser.emitError(loc,
"expected 'public', 'private', or 'nested'");
271 auto visibilityAttr = parser.getBuilder().getStringAttr(visibility);
273 if (parser.parseGreater())
276 return parser.getChecked<InnerSymPropertiesAttr>(parser.getContext(), name,
277 fieldId, visibilityAttr);
280void InnerSymPropertiesAttr::print(AsmPrinter &odsPrinter)
const {
282 << getSymVisibility().getValue() <<
">";
285LogicalResult InnerSymPropertiesAttr::verify(
286 ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError,
287 ::mlir::StringAttr name, uint64_t fieldID,
288 ::mlir::StringAttr symVisibility) {
289 if (!name || name.getValue().empty())
290 return emitError() <<
"inner symbol cannot have empty name";
294StringAttr InnerSymAttr::getSymIfExists(uint64_t fieldId)
const {
296 llvm::find_if(getImpl()->props, [&](
const InnerSymPropertiesAttr &p) {
297 return p.getFieldID() == fieldId;
299 if (it != getProps().
end())
300 return it->getName();
304InnerSymAttr InnerSymAttr::erase(uint64_t fieldID)
const {
305 SmallVector<InnerSymPropertiesAttr> syms(getProps());
306 const auto *it = llvm::find_if(syms, [fieldID](InnerSymPropertiesAttr p) {
307 return p.getFieldID() == fieldID;
311 return InnerSymAttr::get(getContext(), syms);
314LogicalResult InnerSymAttr::walkSymbols(
315 llvm::function_ref<LogicalResult(StringAttr)> callback)
const {
316 for (
auto p : getImpl()->props)
317 if (callback(p.
getName()).failed())
322Attribute InnerSymAttr::parse(AsmParser &parser, Type type) {
324 NamedAttrList dummyList;
325 SmallVector<InnerSymPropertiesAttr, 4> names;
326 if (!parser.parseOptionalSymbolName(sym,
"dummy", dummyList)) {
327 auto prop = parser.getChecked<InnerSymPropertiesAttr>(
328 parser.getContext(), sym, 0,
329 StringAttr::get(parser.getContext(),
"public"));
332 names.push_back(prop);
333 }
else if (parser.parseCommaSeparatedList(
334 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
335 InnerSymPropertiesAttr prop;
336 if (parser.parseCustomAttributeWithFallback(
337 prop, mlir::Type{},
"dummy", dummyList))
340 names.push_back(prop);
346 std::sort(names.begin(), names.end(),
347 [&](InnerSymPropertiesAttr a, InnerSymPropertiesAttr b) {
348 return a.getFieldID() < b.getFieldID();
351 return InnerSymAttr::get(parser.getContext(), names);
354void InnerSymAttr::print(AsmPrinter &odsPrinter)
const {
356 auto props = getProps();
357 if (props.size() == 1 && props[0].getSymVisibility().getValue() ==
"public" &&
358 props[0].getFieldID() == 0) {
359 odsPrinter <<
"@" << props[0].getName().getValue();
362 auto names = props.vec();
364 std::sort(names.begin(), names.end(),
365 [&](InnerSymPropertiesAttr a, InnerSymPropertiesAttr b) {
366 return a.getFieldID() < b.getFieldID();
369 llvm::interleaveComma(names, odsPrinter, [&](InnerSymPropertiesAttr attr) {
370 attr.print(odsPrinter);
379Attribute ParamDeclAttr::parse(AsmParser &p, Type trailing) {
386 if (p.parseLess() || p.parseString(&name) || p.parseColonType(type))
389 if (succeeded(p.parseOptionalEqual())) {
390 if (p.parseAttribute(value, type))
394 if (p.parseGreater())
398 return ParamDeclAttr::get(p.getContext(),
399 p.getBuilder().getStringAttr(name), type, value);
400 return ParamDeclAttr::get(name, type);
403void ParamDeclAttr::print(AsmPrinter &p)
const {
404 p <<
"<" <<
getName() <<
": " << getType();
407 p.printAttributeWithoutType(getValue());
416Attribute ParamDeclRefAttr::parse(AsmParser &p, Type type) {
418 if (p.parseLess() || p.parseAttribute(name) || p.parseGreater() ||
419 (!type && (p.parseColon() || p.parseType(type))))
422 return ParamDeclRefAttr::get(name, type);
425void ParamDeclRefAttr::print(AsmPrinter &p)
const {
433Attribute ParamVerbatimAttr::parse(AsmParser &p, Type type) {
435 if (p.parseLess() || p.parseAttribute(text) || p.parseGreater() ||
436 (!type && (p.parseColon() || p.parseType(type))))
439 return ParamVerbatimAttr::get(p.getContext(), text, type);
442void ParamVerbatimAttr::print(AsmPrinter &p)
const {
443 p <<
"<" << getValue() <<
">";
453 ArrayRef<TypedAttr> operands,
454 llvm::function_ref<APInt(
const APInt &,
const APInt &)> calculate) {
455 assert(operands.size() == 2 &&
"binary operator always has two operands");
456 if (
auto lhs = dyn_cast<IntegerAttr>(operands[0]))
457 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
458 return IntegerAttr::get(lhs.getType(),
459 calculate(lhs.getValue(), rhs.getValue()));
467 llvm::function_ref<APInt(
const APInt &)> calculate) {
468 assert(operands.size() == 1 &&
"unary operator always has one operand");
469 if (
auto intAttr = dyn_cast<IntegerAttr>(operands[0]))
470 return IntegerAttr::get(intAttr.getType(), calculate(intAttr.getValue()));
476static ParamExprAttr
dyn_castPE(PEO opcode, Attribute value) {
477 if (
auto expr = dyn_cast<ParamExprAttr>(value))
478 if (expr.getOpcode() == opcode)
496 if (isa<IntegerAttr>(rhs)) {
499 return !isa<IntegerAttr>(lhs);
501 if (isa<IntegerAttr>(lhs))
505 if (
auto rhsParam = dyn_cast<ParamDeclRefAttr>(rhs)) {
507 if (
auto lhsParam = dyn_cast<ParamDeclRefAttr>(lhs))
508 return lhsParam.getName().getValue() < rhsParam.getName().getValue();
512 if (isa<ParamDeclRefAttr>(lhs))
516 if (
auto rhsParam = dyn_cast<ParamVerbatimAttr>(rhs)) {
518 if (
auto lhsParam = dyn_cast<ParamVerbatimAttr>(lhs))
519 return lhsParam.getValue().getValue() < rhsParam.getValue().getValue();
523 if (isa<ParamVerbatimAttr>(lhs))
527 auto lhsExpr = cast<ParamExprAttr>(lhs), rhsExpr = cast<ParamExprAttr>(rhs);
529 if (lhsExpr.getOpcode() != rhsExpr.getOpcode())
530 return stringifyPEO(lhsExpr.getOpcode()) <
531 stringifyPEO(rhsExpr.getOpcode());
534 ArrayRef<TypedAttr> lhsOperands = lhsExpr.getOperands(),
535 rhsOperands = rhsExpr.getOperands();
536 if (lhsOperands.size() != rhsOperands.size())
537 return lhsOperands.size() > rhsOperands.size();
541 for (
size_t i = 0, e = lhsOperands.size(); i != e; ++i) {
548 llvm_unreachable(
"expressions should never be equivalent");
556 PEO opcode, SmallVector<TypedAttr, 4> &operands,
557 llvm::function_ref<APInt(
const APInt &,
const APInt &)> calculateFn,
558 llvm::function_ref<
bool(
const APInt &)> identityConstantFn,
559 llvm::function_ref<
bool(
const APInt &)> destructiveConstantFn = {}) {
560 auto type = operands[0].getType();
562 if (operands.size() == 1)
567 for (
size_t i = 0, e = operands.size(); i != e; ++i) {
568 if (
auto subexpr =
dyn_castPE(opcode, operands[i])) {
569 std::swap(operands[i], operands.back());
573 operands.append(subexpr.getOperands().begin(),
574 subexpr.getOperands().end());
584 if (isa<IntegerAttr>(operands.back())) {
585 while (operands.size() >= 2 &&
586 isa<IntegerAttr>(operands[operands.size() - 2])) {
587 APInt c1 = cast<IntegerAttr>(operands.pop_back_val()).getValue();
588 APInt c2 = cast<IntegerAttr>(operands.pop_back_val()).getValue();
589 auto resultConstant = IntegerAttr::get(type, calculateFn(c1, c2));
590 operands.push_back(resultConstant);
593 auto resultCst = cast<IntegerAttr>(operands.back());
597 if (destructiveConstantFn && destructiveConstantFn(resultCst.getValue()))
602 if (identityConstantFn(resultCst.getValue()) && operands.size() != 1)
606 return operands.size() == 1 ? operands[0] : TypedAttr();
615 if (
auto cst = dyn_cast<IntegerAttr>(mul.getOperands().back())) {
616 auto nonCst = ParamExprAttr::get(PEO::Mul, mul.getOperands().drop_back());
617 return {nonCst, cst};
619 return {operand, TypedAttr()};
623 return IntegerAttr::get(type, APInt(type.getIntOrFloatBitWidth(), 1));
626static TypedAttr
simplifyAdd(SmallVector<TypedAttr, 4> &operands) {
628 PEO::Add, operands, [](
auto a,
auto b) {
return a + b; },
629 [](
auto cst) {
return cst.isZero(); }))
634 SmallVector<std::pair<TypedAttr, TypedAttr>> decomposedOperands;
635 llvm::SmallDenseSet<TypedAttr> nonConstantParts;
636 for (
auto &op : operands) {
643 if (!nonConstantParts.insert(decomposedOperands.back().first).second) {
645 TypedAttr mulOperand = decomposedOperands.back().first;
649 while (decomposedOperands[i].first != mulOperand)
652 operands.erase(operands.begin() + (&op - &operands[0]));
653 operands.erase(operands.begin() + i);
655 auto type = mulOperand.getType();
656 auto c1 = decomposedOperands[i].second,
657 c2 = decomposedOperands.back().second;
665 auto constant = ParamExprAttr::get(PEO::Add, c1, c2);
666 auto mulCst = ParamExprAttr::get(PEO::Mul, mulOperand, constant);
667 operands.push_back(mulCst);
668 return ParamExprAttr::get(PEO::Add, operands);
675static TypedAttr
simplifyMul(SmallVector<TypedAttr, 4> &operands) {
677 PEO::Mul, operands, [](
auto a,
auto b) {
return a * b; },
678 [](
auto cst) {
return cst.isOne(); },
679 [](
auto cst) {
return cst.isZero(); }))
684 for (
size_t i = 0, e = operands.size(); i != e; ++i) {
685 if (
auto subexpr =
dyn_castPE(PEO::Add, operands[i])) {
688 SmallVector<TypedAttr> mulOperands(operands.begin(), operands.end());
689 mulOperands.erase(mulOperands.begin() + i);
692 SmallVector<TypedAttr> addOperands;
693 for (
auto addOperand : subexpr.getOperands()) {
694 mulOperands.push_back(addOperand);
695 addOperands.push_back(ParamExprAttr::get(PEO::Mul, mulOperands));
696 mulOperands.pop_back();
699 return ParamExprAttr::get(PEO::Add, addOperands);
705static TypedAttr
simplifyAnd(SmallVector<TypedAttr, 4> &operands) {
707 PEO::And, operands, [](
auto a,
auto b) {
return a & b; },
708 [](
auto cst) {
return cst.isAllOnes(); },
709 [](
auto cst) {
return cst.isZero(); });
712static TypedAttr
simplifyOr(SmallVector<TypedAttr, 4> &operands) {
714 PEO::Or, operands, [](
auto a,
auto b) {
return a | b; },
715 [](
auto cst) {
return cst.isZero(); },
716 [](
auto cst) {
return cst.isAllOnes(); });
712static TypedAttr
simplifyOr(SmallVector<TypedAttr, 4> &operands) {
…}
719static TypedAttr
simplifyXor(SmallVector<TypedAttr, 4> &operands) {
721 PEO::Xor, operands, [](
auto a,
auto b) {
return a ^ b; },
722 [](
auto cst) {
return cst.isZero(); });
725static TypedAttr
simplifyShl(SmallVector<TypedAttr, 4> &operands) {
728 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1])) {
730 if (
auto lhs = dyn_cast<IntegerAttr>(operands[0]))
731 return IntegerAttr::get(lhs.getType(),
732 lhs.getValue().shl(rhs.getValue()));
736 auto rhsCst = APInt::getOneBitSet(rhs.getValue().getBitWidth(),
737 rhs.getValue().getZExtValue());
738 return ParamExprAttr::get(PEO::Mul, operands[0],
739 IntegerAttr::get(rhs.getType(), rhsCst));
747 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
748 if (rhs.getValue().isZero())
751 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.lshr(b); });
757 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
758 if (rhs.getValue().isZero())
761 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.ashr(b); });
767 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
768 if (rhs.getValue().isOne())
771 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.udiv(b); });
777 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
778 if (rhs.getValue().isOne())
781 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.sdiv(b); });
787 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
788 if (rhs.getValue().isOne())
789 return IntegerAttr::get(rhs.getType(), 0);
791 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.urem(b); });
797 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
798 if (rhs.getValue().isOne())
799 return IntegerAttr::get(rhs.getType(), 0);
801 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.srem(b); });
808 return APInt(a.getBitWidth(), a == 0 ? 0 : a.ceilLogBase2());
814 SmallVector<TypedAttr> newOperands;
815 SmallVector<StringAttr> stringsToCombine;
816 auto combineAndPush = [&]() {
817 if (stringsToCombine.empty())
820 SmallString<32> newString;
821 for (
auto part : stringsToCombine)
822 newString.append(part.getValue());
823 newOperands.push_back(
824 StringAttr::get(stringsToCombine[0].getContext(), newString));
825 stringsToCombine.clear();
828 for (TypedAttr op : operands) {
829 if (
auto strOp = dyn_cast<StringAttr>(op)) {
831 stringsToCombine.push_back(strOp);
834 newOperands.push_back(op);
839 assert(!newOperands.empty());
840 if (newOperands.size() == 1)
841 return newOperands[0];
842 if (newOperands.size() < operands.size())
843 return ParamExprAttr::get(PEO::StrConcat, newOperands);
849TypedAttr ParamExprAttr::get(PEO opcode, ArrayRef<TypedAttr> operandsIn) {
850 assert(!operandsIn.empty() &&
"Cannot have expr with no operands");
852 auto type = operandsIn.front().getType();
853 assert(llvm::all_of(operandsIn.drop_front(),
854 [&](
auto op) { return op.getType() == type; }));
856 SmallVector<TypedAttr, 4> operands(operandsIn.begin(), operandsIn.end());
909 return Base::get(operands[0].getContext(), opcode, operands, type);
912Attribute ParamExprAttr::parse(AsmParser &p, Type type) {
915 p.emitError(p.getNameLoc(),
"#hw.param.expr should have opcode suffix");
922 DialectAsmParser &p, Type type) {
923 SmallVector<TypedAttr> operands;
924 if (p.parseCommaSeparatedList(
925 mlir::AsmParser::Delimiter::LessGreater, [&]() -> ParseResult {
926 operands.push_back({});
927 return p.parseAttribute(operands.back(), type);
931 std::optional<PEO> opcode = symbolizePEO(opcodeStr);
932 if (!opcode.has_value()) {
933 p.emitError(p.getNameLoc(),
"unknown parameter expr operator name");
937 return ParamExprAttr::get(*opcode, operands);
940void ParamExprAttr::print(AsmPrinter &p)
const {
941 p <<
"." << stringifyPEO(getOpcode()) <<
'<';
942 llvm::interleaveComma(getOperands(), p.getStream(),
943 [&](Attribute op) { p.printAttributeWithoutType(op); });
949static FailureOr<Attribute>
951 const std::map<std::string, Attribute> ¶meters,
952 Attribute paramAttr,
bool emitErrors) {
953 if (dyn_cast<IntegerAttr>(paramAttr)) {
957 if (
auto paramRefAttr = dyn_cast<hw::ParamDeclRefAttr>(paramAttr)) {
959 auto it = parameters.find(paramRefAttr.getName().str());
960 if (it == parameters.end()) {
962 return emitError(loc)
963 <<
"Could not find parameter " << paramRefAttr.getName().str()
964 <<
" in the provided parameters for the expression!";
969 if (
auto paramExprAttr = dyn_cast<hw::ParamExprAttr>(paramAttr)) {
971 llvm::SmallVector<TypedAttr, 4> replacedOperands;
972 for (
auto operand : paramExprAttr.getOperands()) {
976 replacedOperands.push_back(cast<TypedAttr>(*res));
979 hw::ParamExprAttr::get(paramExprAttr.getOpcode(), replacedOperands)};
981 llvm_unreachable(
"Unhandled parametric attribute");
985FailureOr<TypedAttr> hw::evaluateParametricAttr(Location loc,
986 ArrayAttr parameters,
990 std::map<std::string, Attribute> parameterMap;
991 for (
auto param : parameters) {
992 auto paramDecl = cast<ParamDeclAttr>(param);
993 parameterMap[paramDecl.getName().str()] = paramDecl.getValue();
1000 if (failed(paramAttrRes))
1002 paramAttr = *paramAttrRes;
1005 if (isa<IntegerAttr, hw::ParamDeclRefAttr>(paramAttr))
1006 return cast<TypedAttr>(paramAttr);
1007 if (
auto paramExprAttr = dyn_cast<hw::ParamExprAttr>(paramAttr)) {
1011 return ParamExprAttr::get(paramExprAttr.getOpcode(),
1012 paramExprAttr.getOperands());
1015 llvm_unreachable(
"Unhandled parametric attribute");
1019template <
typename TArray>
1021 TArray arrayType,
bool emitErrors) {
1027 loc, parameters, arrayType.getElementType(), emitErrors);
1033 if (
auto intAttr = dyn_cast<IntegerAttr>(*size))
1036 IntegerAttr::get(IntegerType::get(arrayType.getContext(), 64),
1037 intAttr.getValue().getSExtValue()));
1040 return TArray::get(arrayType.getContext(), *
elementType, *size);
1043FailureOr<Type> hw::evaluateParametricType(Location loc, ArrayAttr parameters,
1044 Type type,
bool emitErrors) {
1045 return llvm::TypeSwitch<Type, FailureOr<Type>>(type)
1046 .Case<hw::IntType>([&](hw::IntType t) -> FailureOr<Type> {
1047 auto evaluatedWidth =
1049 if (failed(evaluatedWidth))
1053 if (
auto intAttr = dyn_cast<IntegerAttr>(*evaluatedWidth))
1054 return {IntegerType::get(type.getContext(),
1055 intAttr.getValue().getSExtValue())};
1058 return hw::IntType::get(cast<TypedAttr>(*evaluatedWidth));
1060 .Case<hw::ArrayType, hw::UnpackedArrayType>(
1061 [&](
auto arrayType) -> FailureOr<Type> {
1065 .Default([&](
auto) {
return type; });
1071 return llvm::TypeSwitch<Attribute, bool>(expr)
1072 .Case([](ParamExprAttr attr) {
1075 .Case([](ParamDeclRefAttr) {
return true; })
1076 .Default([](
auto) {
return false; });
1079bool hw::isParametricType(mlir::Type t) {
1080 return llvm::TypeSwitch<Type, bool>(t)
1083 .Case<hw::ArrayType, hw::UnpackedArrayType>([&](
auto arrayType) {
1087 .Default([](
auto) {
return false; });
1079bool hw::isParametricType(mlir::Type t) {
…}
assert(baseType &&"element must be base type")
static TypedAttr foldBinaryOp(ArrayRef< TypedAttr > operands, llvm::function_ref< APInt(const APInt &, const APInt &)> calculate)
Given a binary function, if the two operands are known constant integers, use the specified fold func...
static TypedAttr simplifyDivS(SmallVector< TypedAttr, 4 > &operands)
static std::pair< TypedAttr, TypedAttr > decomposeAddend(TypedAttr operand)
Analyze an operand to an add.
static TypedAttr simplifyAssocOp(PEO opcode, SmallVector< TypedAttr, 4 > &operands, llvm::function_ref< APInt(const APInt &, const APInt &)> calculateFn, llvm::function_ref< bool(const APInt &)> identityConstantFn, llvm::function_ref< bool(const APInt &)> destructiveConstantFn={})
Given a fully associative variadic integer operation, constant fold any constant operands and move th...
static TypedAttr simplifyDivU(SmallVector< TypedAttr, 4 > &operands)
static TypedAttr simplifyCLog2(SmallVector< TypedAttr, 4 > &operands)
static bool isParamAttrWithParamRef(Attribute expr)
static TypedAttr simplifyModU(SmallVector< TypedAttr, 4 > &operands)
static TypedAttr simplifyOr(SmallVector< TypedAttr, 4 > &operands)
static TypedAttr simplifyShl(SmallVector< TypedAttr, 4 > &operands)
static void printSymbolName(AsmPrinter &p, StringAttr sym)
static TypedAttr simplifyShrS(SmallVector< TypedAttr, 4 > &operands)
static FailureOr< Attribute > replaceDeclRefInExpr(Location loc, const std::map< std::string, Attribute > ¶meters, Attribute paramAttr, bool emitErrors)
static TypedAttr foldUnaryOp(ArrayRef< TypedAttr > operands, llvm::function_ref< APInt(const APInt &)> calculate)
Given a unary function, if the operand is a known constant integer, use the specified fold function t...
static TypedAttr simplifyMul(SmallVector< TypedAttr, 4 > &operands)
static TypedAttr getOneOfType(Type type)
static TypedAttr simplifyAnd(SmallVector< TypedAttr, 4 > &operands)
static TypedAttr simplifyModS(SmallVector< TypedAttr, 4 > &operands)
static Attribute parseParamExprWithOpcode(StringRef opcode, DialectAsmParser &p, Type type)
Internal method used for .mlir file parsing when parsing the "#hw.param.expr.mul" form of the attribu...
static bool paramExprOperandSortPredicate(Attribute lhs, Attribute rhs)
This implements a < comparison for two operands to an associative operation imposing an ordering upon...
static std::string canonicalizeFilename(const Twine &directory, const Twine &filename)
static TypedAttr simplifyShrU(SmallVector< TypedAttr, 4 > &operands)
FailureOr< Type > evaluateParametricArrayType(Location loc, ArrayAttr parameters, TArray arrayType, bool emitErrors)
static TypedAttr simplifyAdd(SmallVector< TypedAttr, 4 > &operands)
static TypedAttr simplifyStrConcat(SmallVector< TypedAttr, 4 > &operands)
static TypedAttr simplifyXor(SmallVector< TypedAttr, 4 > &operands)
static ParamExprAttr dyn_castPE(PEO opcode, Attribute value)
If the specified attribute is a ParamExprAttr with the specified opcode, return it.
static unsigned getFieldID(BundleType type, unsigned index)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
mlir::FailureOr< mlir::TypedAttr > evaluateParametricAttr(mlir::Location loc, mlir::ArrayAttr parameters, mlir::Attribute paramAttr, bool emitErrors=true)
Evaluates a parametric attribute (param.decl.ref/param.expr) based on a set of provided parameter val...
bool isHWIntegerType(mlir::Type type)
Return true if the specified type is a value HW Integer type.
mlir::FailureOr< mlir::Type > evaluateParametricType(mlir::Location loc, mlir::ArrayAttr parameters, mlir::Type type, bool emitErrors=true)
Returns a resolved version of 'type' wherein any parameter reference has been evaluated based on the ...
bool isParametricType(mlir::Type t)
Returns true if any part of t is parametric.
mlir::Type getCanonicalType(mlir::Type type)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.