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"
22 using namespace circt;
24 using mlir::TypedAttr;
34 #define GET_ATTRDEF_CLASSES
35 #include "circt/Dialect/HW/HWAttributes.cpp.inc"
37 void HWDialect::registerAttributes() {
39 #define GET_ATTRDEF_LIST
40 #include "circt/Dialect/HW/HWAttributes.cpp.inc"
44 Attribute 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 +
"'");
62 void 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;
101 return std::string(fullPath);
104 OutputFileAttr OutputFileAttr::getFromFilename(MLIRContext *context,
105 const Twine &filename,
106 bool excludeFromFileList,
107 bool includeReplicatedOps) {
108 return OutputFileAttr::getFromDirectoryAndFilename(
109 context,
"", filename, excludeFromFileList, includeReplicatedOps);
112 OutputFileAttr OutputFileAttr::getFromDirectoryAndFilename(
113 MLIRContext *context,
const Twine &directory,
const Twine &filename,
114 bool excludeFromFileList,
bool includeReplicatedOps) {
121 OutputFileAttr OutputFileAttr::getAsDirectory(MLIRContext *context,
122 const Twine &directory,
123 bool excludeFromFileList,
124 bool includeReplicatedOps) {
125 return getFromDirectoryAndFilename(context, directory,
"",
126 excludeFromFileList, includeReplicatedOps);
129 bool OutputFileAttr::isDirectory() {
130 return getFilename().getValue().ends_with(llvm::sys::path::get_separator());
133 StringRef 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();
145 Attribute 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);
174 void OutputFileAttr::print(AsmPrinter &p)
const {
175 p <<
"<" << getFilename();
176 if (getExcludeFromFilelist().getValue())
177 p <<
", excludeFromFileList";
178 if (getIncludeReplicatedOps().getValue())
179 p <<
", includeReplicatedOps";
187 Attribute EnumFieldAttr::parse(AsmParser &p, Type) {
190 if (p.parseLess() || p.parseKeyword(&field) || p.parseComma() ||
191 p.parseType(type) || p.parseGreater())
197 void EnumFieldAttr::print(AsmPrinter &p)
const {
198 p <<
"<" << getField().getValue() <<
", ";
199 p.printType(getType().getValue());
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;
223 Attribute InnerRefAttr::parse(AsmParser &p, Type type) {
225 if (p.parseLess() || p.parseAttribute<SymbolRefAttr>(attr) ||
228 if (attr.getNestedReferences().size() != 1)
235 p.printSymbolName(sym.getValue());
237 p.printSymbolName({});
240 void InnerRefAttr::print(AsmPrinter &p)
const {
252 Attribute InnerSymPropertiesAttr::parse(AsmParser &parser, Type type) {
254 NamedAttrList dummyList;
256 if (parser.parseLess() || parser.parseSymbolName(name,
"name", dummyList) ||
257 parser.parseComma() || parser.parseInteger(fieldId) ||
261 StringRef visibility;
262 auto loc = parser.getCurrentLocation();
263 if (parser.parseOptionalKeyword(&visibility,
264 {
"public",
"private",
"nested"})) {
265 parser.emitError(loc,
"expected 'public', 'private', or 'nested'");
268 auto visibilityAttr = parser.getBuilder().getStringAttr(visibility);
270 if (parser.parseGreater())
273 return parser.getChecked<InnerSymPropertiesAttr>(parser.getContext(), name,
274 fieldId, visibilityAttr);
277 void InnerSymPropertiesAttr::print(AsmPrinter &odsPrinter)
const {
279 << getSymVisibility().getValue() <<
">";
283 ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError,
284 ::mlir::StringAttr name, uint64_t fieldID,
285 ::mlir::StringAttr symVisibility) {
286 if (!name || name.getValue().empty())
287 return emitError() <<
"inner symbol cannot have empty name";
291 StringAttr InnerSymAttr::getSymIfExists(uint64_t fieldId)
const {
293 llvm::find_if(getImpl()->props, [&](
const InnerSymPropertiesAttr &p) {
294 return p.getFieldID() == fieldId;
296 if (it != getProps().
end())
297 return it->getName();
301 InnerSymAttr InnerSymAttr::erase(uint64_t fieldID)
const {
302 SmallVector<InnerSymPropertiesAttr> syms(getProps());
303 const auto *it = llvm::find_if(syms, [fieldID](InnerSymPropertiesAttr p) {
304 return p.getFieldID() == fieldID;
311 LogicalResult InnerSymAttr::walkSymbols(
312 llvm::function_ref<LogicalResult(StringAttr)> callback)
const {
313 for (
auto p : getImpl()->props)
314 if (callback(p.getName()).failed())
319 Attribute InnerSymAttr::parse(AsmParser &parser, Type type) {
321 NamedAttrList dummyList;
322 SmallVector<InnerSymPropertiesAttr, 4> names;
323 if (!parser.parseOptionalSymbolName(sym,
"dummy", dummyList)) {
324 auto prop = parser.getChecked<InnerSymPropertiesAttr>(
325 parser.getContext(), sym, 0,
329 names.push_back(prop);
330 }
else if (parser.parseCommaSeparatedList(
331 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
332 InnerSymPropertiesAttr prop;
333 if (parser.parseCustomAttributeWithFallback(
334 prop, mlir::Type{},
"dummy", dummyList))
337 names.push_back(prop);
343 std::sort(names.begin(), names.end(),
344 [&](InnerSymPropertiesAttr a, InnerSymPropertiesAttr b) {
345 return a.getFieldID() < b.getFieldID();
351 void InnerSymAttr::print(AsmPrinter &odsPrinter)
const {
353 auto props = getProps();
354 if (props.size() == 1 && props[0].getSymVisibility().getValue() ==
"public" &&
355 props[0].getFieldID() == 0) {
356 odsPrinter <<
"@" << props[0].getName().getValue();
359 auto names = props.vec();
361 std::sort(names.begin(), names.end(),
362 [&](InnerSymPropertiesAttr a, InnerSymPropertiesAttr b) {
363 return a.getFieldID() < b.getFieldID();
366 llvm::interleaveComma(names, odsPrinter, [&](InnerSymPropertiesAttr attr) {
367 attr.print(odsPrinter);
376 Attribute ParamDeclAttr::parse(AsmParser &p, Type trailing) {
383 if (p.parseLess() || p.parseString(&name) || p.parseColonType(type))
386 if (succeeded(p.parseOptionalEqual())) {
387 if (p.parseAttribute(value, type))
391 if (p.parseGreater())
396 p.getBuilder().getStringAttr(name), type, value);
400 void ParamDeclAttr::print(AsmPrinter &p)
const {
401 p <<
"<" <<
getName() <<
": " << getType();
404 p.printAttributeWithoutType(getValue());
413 Attribute ParamDeclRefAttr::parse(AsmParser &p, Type type) {
415 if (p.parseLess() || p.parseAttribute(name) || p.parseGreater() ||
416 (!type && (p.parseColon() || p.parseType(type))))
422 void ParamDeclRefAttr::print(AsmPrinter &p)
const {
430 Attribute ParamVerbatimAttr::parse(AsmParser &p, Type type) {
432 if (p.parseLess() || p.parseAttribute(text) || p.parseGreater() ||
433 (!type && (p.parseColon() || p.parseType(type))))
439 void ParamVerbatimAttr::print(AsmPrinter &p)
const {
440 p <<
"<" << getValue() <<
">";
450 ArrayRef<TypedAttr> operands,
451 llvm::function_ref<APInt(
const APInt &,
const APInt &)> calculate) {
452 assert(operands.size() == 2 &&
"binary operator always has two operands");
453 if (
auto lhs = dyn_cast<IntegerAttr>(operands[0]))
454 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
456 calculate(lhs.getValue(), rhs.getValue()));
464 llvm::function_ref<APInt(
const APInt &)> calculate) {
465 assert(operands.size() == 1 &&
"unary operator always has one operand");
466 if (
auto intAttr = dyn_cast<IntegerAttr>(operands[0]))
473 static ParamExprAttr
dyn_castPE(PEO opcode, Attribute value) {
474 if (
auto expr = dyn_cast<ParamExprAttr>(value))
475 if (expr.getOpcode() == opcode)
493 if (isa<IntegerAttr>(rhs)) {
496 return !isa<IntegerAttr>(lhs);
498 if (isa<IntegerAttr>(lhs))
502 if (
auto rhsParam = dyn_cast<ParamDeclRefAttr>(rhs)) {
504 if (
auto lhsParam = dyn_cast<ParamDeclRefAttr>(lhs))
505 return lhsParam.getName().getValue() < rhsParam.getName().getValue();
509 if (isa<ParamDeclRefAttr>(lhs))
513 if (
auto rhsParam = dyn_cast<ParamVerbatimAttr>(rhs)) {
515 if (
auto lhsParam = dyn_cast<ParamVerbatimAttr>(lhs))
516 return lhsParam.getValue().getValue() < rhsParam.getValue().getValue();
520 if (isa<ParamVerbatimAttr>(lhs))
524 auto lhsExpr = cast<ParamExprAttr>(lhs), rhsExpr = cast<ParamExprAttr>(rhs);
526 if (lhsExpr.getOpcode() != rhsExpr.getOpcode())
527 return stringifyPEO(lhsExpr.getOpcode()) <
528 stringifyPEO(rhsExpr.getOpcode());
531 ArrayRef<TypedAttr> lhsOperands = lhsExpr.getOperands(),
532 rhsOperands = rhsExpr.getOperands();
533 if (lhsOperands.size() != rhsOperands.size())
534 return lhsOperands.size() > rhsOperands.size();
538 for (
size_t i = 0, e = lhsOperands.size(); i != e; ++i) {
545 llvm_unreachable(
"expressions should never be equivalent");
553 PEO opcode, SmallVector<TypedAttr, 4> &operands,
554 llvm::function_ref<APInt(
const APInt &,
const APInt &)> calculateFn,
555 llvm::function_ref<
bool(
const APInt &)> identityConstantFn,
556 llvm::function_ref<
bool(
const APInt &)> destructiveConstantFn = {}) {
557 auto type = operands[0].getType();
559 if (operands.size() == 1)
564 for (
size_t i = 0, e = operands.size(); i != e; ++i) {
565 if (
auto subexpr =
dyn_castPE(opcode, operands[i])) {
566 std::swap(operands[i], operands.back());
570 operands.append(subexpr.getOperands().begin(),
571 subexpr.getOperands().end());
581 if (isa<IntegerAttr>(operands.back())) {
582 while (operands.size() >= 2 &&
583 isa<IntegerAttr>(operands[operands.size() - 2])) {
584 APInt c1 = cast<IntegerAttr>(operands.pop_back_val()).getValue();
585 APInt c2 = cast<IntegerAttr>(operands.pop_back_val()).getValue();
587 operands.push_back(resultConstant);
590 auto resultCst = cast<IntegerAttr>(operands.back());
594 if (destructiveConstantFn && destructiveConstantFn(resultCst.getValue()))
599 if (identityConstantFn(resultCst.getValue()) && operands.size() != 1)
603 return operands.size() == 1 ? operands[0] : TypedAttr();
612 if (
auto cst = dyn_cast<IntegerAttr>(mul.getOperands().back())) {
614 return {nonCst, cst};
616 return {operand, TypedAttr()};
623 static TypedAttr
simplifyAdd(SmallVector<TypedAttr, 4> &operands) {
625 PEO::Add, operands, [](
auto a,
auto b) {
return a + b; },
626 [](
auto cst) {
return cst.isZero(); }))
631 SmallVector<std::pair<TypedAttr, TypedAttr>> decomposedOperands;
632 llvm::SmallDenseSet<TypedAttr> nonConstantParts;
633 for (
auto &op : operands) {
640 if (!nonConstantParts.insert(decomposedOperands.back().first).second) {
642 TypedAttr mulOperand = decomposedOperands.back().first;
646 while (decomposedOperands[i].first != mulOperand)
649 operands.erase(operands.begin() + (&op - &operands[0]));
650 operands.erase(operands.begin() + i);
652 auto type = mulOperand.getType();
653 auto c1 = decomposedOperands[i].second,
654 c2 = decomposedOperands.back().second;
664 operands.push_back(mulCst);
672 static TypedAttr
simplifyMul(SmallVector<TypedAttr, 4> &operands) {
674 PEO::Mul, operands, [](
auto a,
auto b) {
return a * b; },
675 [](
auto cst) {
return cst.isOne(); },
676 [](
auto cst) {
return cst.isZero(); }))
681 for (
size_t i = 0, e = operands.size(); i != e; ++i) {
682 if (
auto subexpr =
dyn_castPE(PEO::Add, operands[i])) {
685 SmallVector<TypedAttr> mulOperands(operands.begin(), operands.end());
686 mulOperands.erase(mulOperands.begin() + i);
689 SmallVector<TypedAttr> addOperands;
690 for (
auto addOperand : subexpr.getOperands()) {
691 mulOperands.push_back(addOperand);
693 mulOperands.pop_back();
702 static TypedAttr
simplifyAnd(SmallVector<TypedAttr, 4> &operands) {
704 PEO::And, operands, [](
auto a,
auto b) {
return a & b; },
705 [](
auto cst) {
return cst.isAllOnes(); },
706 [](
auto cst) {
return cst.isZero(); });
709 static TypedAttr
simplifyOr(SmallVector<TypedAttr, 4> &operands) {
711 PEO::Or, operands, [](
auto a,
auto b) {
return a | b; },
712 [](
auto cst) {
return cst.isZero(); },
713 [](
auto cst) {
return cst.isAllOnes(); });
716 static TypedAttr
simplifyXor(SmallVector<TypedAttr, 4> &operands) {
718 PEO::Xor, operands, [](
auto a,
auto b) {
return a ^ b; },
719 [](
auto cst) {
return cst.isZero(); });
722 static TypedAttr
simplifyShl(SmallVector<TypedAttr, 4> &operands) {
725 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1])) {
727 if (
auto lhs = dyn_cast<IntegerAttr>(operands[0]))
729 lhs.getValue().shl(rhs.getValue()));
733 auto rhsCst = APInt::getOneBitSet(rhs.getValue().getBitWidth(),
734 rhs.getValue().getZExtValue());
744 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
745 if (rhs.getValue().isZero())
748 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.lshr(b); });
754 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
755 if (rhs.getValue().isZero())
758 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.ashr(b); });
764 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
765 if (rhs.getValue().isOne())
768 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.udiv(b); });
774 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
775 if (rhs.getValue().isOne())
778 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.sdiv(b); });
784 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
785 if (rhs.getValue().isOne())
788 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.urem(b); });
794 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
795 if (rhs.getValue().isOne())
798 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.srem(b); });
805 return APInt(a.getBitWidth(), a == 0 ? 0 : a.ceilLogBase2());
811 SmallVector<TypedAttr> newOperands;
812 SmallVector<StringAttr> stringsToCombine;
813 auto combineAndPush = [&]() {
814 if (stringsToCombine.empty())
817 SmallString<32> newString;
818 for (
auto part : stringsToCombine)
819 newString.append(part.getValue());
820 newOperands.push_back(
822 stringsToCombine.clear();
825 for (TypedAttr op : operands) {
826 if (
auto strOp = dyn_cast<StringAttr>(op)) {
828 stringsToCombine.push_back(strOp);
831 newOperands.push_back(op);
836 assert(!newOperands.empty());
837 if (newOperands.size() == 1)
838 return newOperands[0];
839 if (newOperands.size() < operands.size())
847 assert(!operandsIn.empty() &&
"Cannot have expr with no operands");
849 auto type = operandsIn.front().getType();
850 assert(llvm::all_of(operandsIn.drop_front(),
851 [&](
auto op) { return op.getType() == type; }));
853 SmallVector<TypedAttr, 4> operands(operandsIn.begin(), operandsIn.end());
906 return Base::get(operands[0].getContext(), opcode, operands, type);
909 Attribute ParamExprAttr::parse(AsmParser &p, Type type) {
912 p.emitError(p.getNameLoc(),
"#hw.param.expr should have opcode suffix");
919 DialectAsmParser &p, Type type) {
920 SmallVector<TypedAttr> operands;
921 if (p.parseCommaSeparatedList(
922 mlir::AsmParser::Delimiter::LessGreater, [&]() -> ParseResult {
923 operands.push_back({});
924 return p.parseAttribute(operands.back(), type);
928 std::optional<PEO> opcode = symbolizePEO(opcodeStr);
929 if (!opcode.has_value()) {
930 p.emitError(p.getNameLoc(),
"unknown parameter expr operator name");
937 void ParamExprAttr::print(AsmPrinter &p)
const {
938 p <<
"." << stringifyPEO(getOpcode()) <<
'<';
939 llvm::interleaveComma(getOperands(), p.getStream(),
940 [&](Attribute op) { p.printAttributeWithoutType(op); });
944 // Replaces any ParamDeclRefAttr within a parametric expression with its
945 // corresponding value from the map of provided parameters.
946 static FailureOr<Attribute>
947 replaceDeclRefInExpr(Location loc,
948 const std::map<std::string, Attribute> ¶meters,
949 Attribute paramAttr, bool emitErrors) {
950 if (dyn_cast<IntegerAttr>(paramAttr)) {
951 // Nothing to do, constant value.
954 if (auto paramRefAttr = dyn_cast<hw::ParamDeclRefAttr>(paramAttr)) {
955 // Get the value from the provided parameters.
956 auto it = parameters.find(paramRefAttr.getName().str());
957 if (it == parameters.end()) {
959 return emitError(loc)
960 << "Could not find parameter " << paramRefAttr.getName().str()
961 << " in the provided parameters for the expression!";
966 if (auto paramExprAttr = dyn_cast<hw::ParamExprAttr>(paramAttr)) {
967 // Recurse into all operands of the expression.
968 llvm::SmallVector<TypedAttr, 4> replacedOperands;
969 for (auto operand : paramExprAttr.getOperands()) {
970 auto res = replaceDeclRefInExpr(loc, parameters, operand, emitErrors);
973 replacedOperands.push_back(cast<TypedAttr>(*res));
976 hw::ParamExprAttr::get(paramExprAttr.getOpcode(), replacedOperands)};
978 llvm_unreachable("Unhandled parametric attribute");
982 FailureOr<TypedAttr> hw::evaluateParametricAttr(Location loc,
983 ArrayAttr parameters,
986 // Create a map of the provided parameters for faster lookup.
987 std::map<std::string, Attribute> parameterMap;
988 for (auto param : parameters) {
989 auto paramDecl = cast<ParamDeclAttr>(param);
990 parameterMap[paramDecl.getName().str()] = paramDecl.getValue();
993 // First, replace any ParamDeclRefAttr in the expression with its
994 // corresponding value in 'parameters
'.
996 replaceDeclRefInExpr(loc, parameterMap, paramAttr, emitErrors);
997 if (failed(paramAttrRes))
999 paramAttr = *paramAttrRes;
1001 // Then, evaluate the parametric attribute.
1002 if (isa<IntegerAttr, hw::ParamDeclRefAttr>(paramAttr))
1003 return cast<TypedAttr>(paramAttr);
1004 if (auto paramExprAttr = dyn_cast<hw::ParamExprAttr>(paramAttr)) {
1005 // Since any ParamDeclRefAttr was replaced within the expression,
1006 // we re-evaluate the expression through the existing ParamExprAttr
1008 return ParamExprAttr::get(paramExprAttr.getOpcode(),
1009 paramExprAttr.getOperands());
1012 llvm_unreachable("Unhandled parametric attribute");
1016 template <typename TArray>
1017 FailureOr<Type> evaluateParametricArrayType(Location loc, ArrayAttr parameters,
1018 TArray arrayType, bool emitErrors) {
1019 auto size = evaluateParametricAttr(loc, parameters, arrayType.getSizeAttr(),
1023 auto elementType = evaluateParametricType(
1024 loc, parameters, arrayType.getElementType(), emitErrors);
1025 if (failed(elementType))
1028 // If the size was evaluated to a constant, use a 64-bit integer
1029 // attribute version of it
1030 if (auto intAttr = dyn_cast<IntegerAttr>(*size))
1032 arrayType.getContext(), *elementType,
1033 IntegerAttr::get(IntegerType::get(arrayType.getContext(), 64),
1034 intAttr.getValue().getSExtValue()));
1036 // Otherwise parameter references are still involved
1037 return TArray::get(arrayType.getContext(), *elementType, *size);
1040 FailureOr<Type> hw::evaluateParametricType(Location loc, ArrayAttr parameters,
1041 Type type, bool emitErrors) {
1042 return llvm::TypeSwitch<Type, FailureOr<Type>>(type)
1043 .Case<hw::IntType>([&](hw::IntType t) -> FailureOr<Type> {
1044 auto evaluatedWidth =
1045 evaluateParametricAttr(loc, parameters, t.getWidth(), emitErrors);
1046 if (failed(evaluatedWidth))
1049 // If the width was evaluated to a constant, return an `IntegerType`
1050 if (auto intAttr = dyn_cast<IntegerAttr>(*evaluatedWidth))
1051 return {IntegerType::get(type.getContext(),
1052 intAttr.getValue().getSExtValue())};
1054 // Otherwise parameter references are still involved
1055 return hw::IntType::get(cast<TypedAttr>(*evaluatedWidth));
1057 .Case<hw::ArrayType, hw::UnpackedArrayType>(
1058 [&](auto arrayType) -> FailureOr<Type> {
1059 return evaluateParametricArrayType(loc, parameters, arrayType,
1062 .Default([&](auto) { return type; });
1065 // Returns true if any part of this parametric attribute contains a reference
1066 // to a parameter declaration.
1067 static bool isParamAttrWithParamRef(Attribute expr) {
1068 return llvm::TypeSwitch<Attribute, bool>(expr)
1069 .Case([](ParamExprAttr attr) {
1070 return llvm::any_of(attr.getOperands(), isParamAttrWithParamRef);
1072 .Case([](ParamDeclRefAttr) { return true; })
1073 .Default([](auto) { return false; });
1076 bool hw::isParametricType(mlir::Type t) {
1077 return llvm::TypeSwitch<Type, bool>(t)
1079 [&](hw::IntType t) { return isParamAttrWithParamRef(t.getWidth()); })
1080 .Case<hw::ArrayType, hw::UnpackedArrayType>([&](auto arrayType) {
1081 return isParametricType(arrayType.getElementType()) ||
1082 isParamAttrWithParamRef(arrayType.getSizeAttr());
1084 .Default([](auto) { return false; });
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 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 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 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 std::pair< TypedAttr, TypedAttr > decomposeAddend(TypedAttr operand)
Analyze an operand to an add.
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)
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 StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
static LogicalResult verify(Value clock, bool eventExists, mlir::Location loc)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
uint64_t getFieldID(Type type, uint64_t 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.
bool isHWIntegerType(mlir::Type type)
Return true if the specified type is a value HW Integer type.
bool isHWEnumType(mlir::Type type)
Return true if the specified type is a HW Enum type.
mlir::Type getCanonicalType(mlir::Type type)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.