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());
135 Attribute OutputFileAttr::parse(AsmParser &p, Type type) {
137 if (p.parseLess() || p.parseAttribute<StringAttr>(filename))
142 bool excludeFromFileList =
false;
143 bool includeReplicatedOps =
false;
145 if (p.parseOptionalComma())
147 if (!p.parseOptionalKeyword(
"excludeFromFileList"))
148 excludeFromFileList =
true;
149 else if (!p.parseKeyword(
"includeReplicatedOps",
150 "or 'excludeFromFileList'"))
151 includeReplicatedOps =
true;
156 if (p.parseGreater())
159 return OutputFileAttr::getFromFilename(p.getContext(), filename.getValue(),
161 includeReplicatedOps);
164 void OutputFileAttr::print(AsmPrinter &p)
const {
165 p <<
"<" << getFilename();
166 if (getExcludeFromFilelist().getValue())
167 p <<
", excludeFromFileList";
168 if (getIncludeReplicatedOps().getValue())
169 p <<
", includeReplicatedOps";
177 Attribute EnumFieldAttr::parse(AsmParser &p, Type) {
180 if (p.parseLess() || p.parseKeyword(&field) || p.parseComma() ||
181 p.parseType(type) || p.parseGreater())
187 void EnumFieldAttr::print(AsmPrinter &p)
const {
188 p <<
"<" << getField().getValue() <<
", ";
189 p.printType(getType().getValue());
196 emitError(loc) <<
"expected enum type";
200 if (!enumType.contains(value.getValue())) {
201 emitError(loc) <<
"enum value '" << value.getValue()
202 <<
"' is not a member of enum type " << enumType;
213 Attribute InnerRefAttr::parse(AsmParser &p, Type type) {
215 if (p.parseLess() || p.parseAttribute<SymbolRefAttr>(attr) ||
218 if (attr.getNestedReferences().size() != 1)
225 p.printSymbolName(sym.getValue());
227 p.printSymbolName({});
230 void InnerRefAttr::print(AsmPrinter &p)
const {
242 Attribute InnerSymPropertiesAttr::parse(AsmParser &parser, Type type) {
244 NamedAttrList dummyList;
246 if (parser.parseLess() || parser.parseSymbolName(name,
"name", dummyList) ||
247 parser.parseComma() || parser.parseInteger(fieldId) ||
251 StringRef visibility;
252 auto loc = parser.getCurrentLocation();
253 if (parser.parseOptionalKeyword(&visibility,
254 {
"public",
"private",
"nested"})) {
255 parser.emitError(loc,
"expected 'public', 'private', or 'nested'");
258 auto visibilityAttr = parser.getBuilder().getStringAttr(visibility);
260 if (parser.parseGreater())
263 return parser.getChecked<InnerSymPropertiesAttr>(parser.getContext(), name,
264 fieldId, visibilityAttr);
267 void InnerSymPropertiesAttr::print(AsmPrinter &odsPrinter)
const {
269 << getSymVisibility().getValue() <<
">";
272 LogicalResult InnerSymPropertiesAttr::verify(
273 ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError,
274 ::mlir::StringAttr name, uint64_t fieldID,
275 ::mlir::StringAttr symVisibility) {
276 if (!name || name.getValue().empty())
277 return emitError() <<
"inner symbol cannot have empty name";
281 StringAttr InnerSymAttr::getSymIfExists(uint64_t fieldId)
const {
283 llvm::find_if(getImpl()->props, [&](
const InnerSymPropertiesAttr &p) {
284 return p.getFieldID() == fieldId;
286 if (it != getProps().
end())
287 return it->getName();
291 InnerSymAttr InnerSymAttr::erase(uint64_t fieldID)
const {
292 SmallVector<InnerSymPropertiesAttr> syms(getProps());
293 const auto *it = llvm::find_if(syms, [fieldID](InnerSymPropertiesAttr p) {
294 return p.getFieldID() == fieldID;
301 LogicalResult InnerSymAttr::walkSymbols(
302 llvm::function_ref<LogicalResult(StringAttr)> callback)
const {
303 for (
auto p : getImpl()->props)
304 if (callback(p.getName()).failed())
309 Attribute InnerSymAttr::parse(AsmParser &parser, Type type) {
311 NamedAttrList dummyList;
312 SmallVector<InnerSymPropertiesAttr, 4> names;
313 if (!parser.parseOptionalSymbolName(sym,
"dummy", dummyList)) {
314 auto prop = parser.getChecked<InnerSymPropertiesAttr>(
315 parser.getContext(), sym, 0,
319 names.push_back(prop);
320 }
else if (parser.parseCommaSeparatedList(
321 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
322 InnerSymPropertiesAttr prop;
323 if (parser.parseCustomAttributeWithFallback(
324 prop, mlir::Type{},
"dummy", dummyList))
327 names.push_back(prop);
333 std::sort(names.begin(), names.end(),
334 [&](InnerSymPropertiesAttr a, InnerSymPropertiesAttr b) {
335 return a.getFieldID() < b.getFieldID();
341 void InnerSymAttr::print(AsmPrinter &odsPrinter)
const {
343 auto props = getProps();
344 if (props.size() == 1 &&
345 props[0].getSymVisibility().getValue().equals(
"public") &&
346 props[0].getFieldID() == 0) {
347 odsPrinter <<
"@" << props[0].getName().getValue();
350 auto names = props.vec();
352 std::sort(names.begin(), names.end(),
353 [&](InnerSymPropertiesAttr a, InnerSymPropertiesAttr b) {
354 return a.getFieldID() < b.getFieldID();
357 llvm::interleaveComma(names, odsPrinter, [&](InnerSymPropertiesAttr attr) {
358 attr.print(odsPrinter);
367 Attribute ParamDeclAttr::parse(AsmParser &p, Type trailing) {
374 if (p.parseLess() || p.parseString(&name) || p.parseColonType(type))
377 if (succeeded(p.parseOptionalEqual())) {
378 if (p.parseAttribute(value, type))
382 if (p.parseGreater())
387 p.getBuilder().getStringAttr(name), type, value);
391 void ParamDeclAttr::print(AsmPrinter &p)
const {
392 p <<
"<" <<
getName() <<
": " << getType();
395 p.printAttributeWithoutType(getValue());
404 Attribute ParamDeclRefAttr::parse(AsmParser &p, Type type) {
406 if (p.parseLess() || p.parseAttribute(name) || p.parseGreater() ||
407 (!type && (p.parseColon() || p.parseType(type))))
413 void ParamDeclRefAttr::print(AsmPrinter &p)
const {
421 Attribute ParamVerbatimAttr::parse(AsmParser &p, Type type) {
423 if (p.parseLess() || p.parseAttribute(text) || p.parseGreater() ||
424 (!type && (p.parseColon() || p.parseType(type))))
430 void ParamVerbatimAttr::print(AsmPrinter &p)
const {
431 p <<
"<" << getValue() <<
">";
441 ArrayRef<TypedAttr> operands,
442 llvm::function_ref<APInt(
const APInt &,
const APInt &)> calculate) {
443 assert(operands.size() == 2 &&
"binary operator always has two operands");
444 if (
auto lhs = dyn_cast<IntegerAttr>(operands[0]))
445 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
447 calculate(lhs.getValue(), rhs.getValue()));
455 llvm::function_ref<APInt(
const APInt &)> calculate) {
456 assert(operands.size() == 1 &&
"unary operator always has one operand");
457 if (
auto intAttr = dyn_cast<IntegerAttr>(operands[0]))
464 static ParamExprAttr
dyn_castPE(PEO opcode, Attribute value) {
465 if (
auto expr = dyn_cast<ParamExprAttr>(value))
466 if (expr.getOpcode() == opcode)
484 if (isa<IntegerAttr>(rhs)) {
487 return !isa<IntegerAttr>(lhs);
489 if (isa<IntegerAttr>(lhs))
493 if (
auto rhsParam = dyn_cast<ParamDeclRefAttr>(rhs)) {
495 if (
auto lhsParam = dyn_cast<ParamDeclRefAttr>(lhs))
496 return lhsParam.getName().getValue() < rhsParam.getName().getValue();
500 if (isa<ParamDeclRefAttr>(lhs))
504 if (
auto rhsParam = dyn_cast<ParamVerbatimAttr>(rhs)) {
506 if (
auto lhsParam = dyn_cast<ParamVerbatimAttr>(lhs))
507 return lhsParam.getValue().getValue() < rhsParam.getValue().getValue();
511 if (isa<ParamVerbatimAttr>(lhs))
515 auto lhsExpr = cast<ParamExprAttr>(lhs), rhsExpr = cast<ParamExprAttr>(rhs);
517 if (lhsExpr.getOpcode() != rhsExpr.getOpcode())
518 return stringifyPEO(lhsExpr.getOpcode()) <
519 stringifyPEO(rhsExpr.getOpcode());
522 ArrayRef<TypedAttr> lhsOperands = lhsExpr.getOperands(),
523 rhsOperands = rhsExpr.getOperands();
524 if (lhsOperands.size() != rhsOperands.size())
525 return lhsOperands.size() > rhsOperands.size();
529 for (
size_t i = 0, e = lhsOperands.size(); i != e; ++i) {
536 llvm_unreachable(
"expressions should never be equivalent");
544 PEO opcode, SmallVector<TypedAttr, 4> &operands,
545 llvm::function_ref<APInt(
const APInt &,
const APInt &)> calculateFn,
546 llvm::function_ref<
bool(
const APInt &)> identityConstantFn,
547 llvm::function_ref<
bool(
const APInt &)> destructiveConstantFn = {}) {
548 auto type = operands[0].getType();
550 if (operands.size() == 1)
555 for (
size_t i = 0, e = operands.size(); i != e; ++i) {
556 if (
auto subexpr =
dyn_castPE(opcode, operands[i])) {
557 std::swap(operands[i], operands.back());
561 operands.append(subexpr.getOperands().begin(),
562 subexpr.getOperands().end());
572 if (isa<IntegerAttr>(operands.back())) {
573 while (operands.size() >= 2 &&
574 isa<IntegerAttr>(operands[operands.size() - 2])) {
575 APInt c1 = cast<IntegerAttr>(operands.pop_back_val()).getValue();
576 APInt c2 = cast<IntegerAttr>(operands.pop_back_val()).getValue();
578 operands.push_back(resultConstant);
581 auto resultCst = cast<IntegerAttr>(operands.back());
585 if (destructiveConstantFn && destructiveConstantFn(resultCst.getValue()))
590 if (identityConstantFn(resultCst.getValue()) && operands.size() != 1)
594 return operands.size() == 1 ? operands[0] : TypedAttr();
603 if (
auto cst = dyn_cast<IntegerAttr>(mul.getOperands().back())) {
605 return {nonCst, cst};
607 return {operand, TypedAttr()};
614 static TypedAttr
simplifyAdd(SmallVector<TypedAttr, 4> &operands) {
616 PEO::Add, operands, [](
auto a,
auto b) {
return a + b; },
617 [](
auto cst) {
return cst.isZero(); }))
622 SmallVector<std::pair<TypedAttr, TypedAttr>> decomposedOperands;
623 llvm::SmallDenseSet<TypedAttr> nonConstantParts;
624 for (
auto &op : operands) {
631 if (!nonConstantParts.insert(decomposedOperands.back().first).second) {
633 TypedAttr mulOperand = decomposedOperands.back().first;
637 while (decomposedOperands[i].first != mulOperand)
640 operands.erase(operands.begin() + (&op - &operands[0]));
641 operands.erase(operands.begin() + i);
643 auto type = mulOperand.getType();
644 auto c1 = decomposedOperands[i].second,
645 c2 = decomposedOperands.back().second;
655 operands.push_back(mulCst);
663 static TypedAttr
simplifyMul(SmallVector<TypedAttr, 4> &operands) {
665 PEO::Mul, operands, [](
auto a,
auto b) {
return a * b; },
666 [](
auto cst) {
return cst.isOne(); },
667 [](
auto cst) {
return cst.isZero(); }))
672 for (
size_t i = 0, e = operands.size(); i != e; ++i) {
673 if (
auto subexpr =
dyn_castPE(PEO::Add, operands[i])) {
676 SmallVector<TypedAttr> mulOperands(operands.begin(), operands.end());
677 mulOperands.erase(mulOperands.begin() + i);
680 SmallVector<TypedAttr> addOperands;
681 for (
auto addOperand : subexpr.getOperands()) {
682 mulOperands.push_back(addOperand);
684 mulOperands.pop_back();
693 static TypedAttr
simplifyAnd(SmallVector<TypedAttr, 4> &operands) {
695 PEO::And, operands, [](
auto a,
auto b) {
return a & b; },
696 [](
auto cst) {
return cst.isAllOnes(); },
697 [](
auto cst) {
return cst.isZero(); });
700 static TypedAttr
simplifyOr(SmallVector<TypedAttr, 4> &operands) {
702 PEO::Or, operands, [](
auto a,
auto b) {
return a | b; },
703 [](
auto cst) {
return cst.isZero(); },
704 [](
auto cst) {
return cst.isAllOnes(); });
707 static TypedAttr
simplifyXor(SmallVector<TypedAttr, 4> &operands) {
709 PEO::Xor, operands, [](
auto a,
auto b) {
return a ^ b; },
710 [](
auto cst) {
return cst.isZero(); });
713 static TypedAttr
simplifyShl(SmallVector<TypedAttr, 4> &operands) {
716 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1])) {
718 if (
auto lhs = dyn_cast<IntegerAttr>(operands[0]))
720 lhs.getValue().shl(rhs.getValue()));
724 auto rhsCst = APInt::getOneBitSet(rhs.getValue().getBitWidth(),
725 rhs.getValue().getZExtValue());
735 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
736 if (rhs.getValue().isZero())
739 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.lshr(b); });
745 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
746 if (rhs.getValue().isZero())
749 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.ashr(b); });
755 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
756 if (rhs.getValue().isOne())
759 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.udiv(b); });
765 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
766 if (rhs.getValue().isOne())
769 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.sdiv(b); });
775 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
776 if (rhs.getValue().isOne())
779 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.urem(b); });
785 if (
auto rhs = dyn_cast<IntegerAttr>(operands[1]))
786 if (rhs.getValue().isOne())
789 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.srem(b); });
796 return APInt(a.getBitWidth(), a == 0 ? 0 : a.ceilLogBase2());
802 SmallVector<TypedAttr> newOperands;
803 SmallVector<StringAttr> stringsToCombine;
804 auto combineAndPush = [&]() {
805 if (stringsToCombine.empty())
808 SmallString<32> newString;
809 for (
auto part : stringsToCombine)
810 newString.append(part.getValue());
811 newOperands.push_back(
813 stringsToCombine.clear();
816 for (TypedAttr op : operands) {
817 if (
auto strOp = dyn_cast<StringAttr>(op)) {
819 stringsToCombine.push_back(strOp);
822 newOperands.push_back(op);
827 assert(!newOperands.empty());
828 if (newOperands.size() == 1)
829 return newOperands[0];
830 if (newOperands.size() < operands.size())
838 assert(!operandsIn.empty() &&
"Cannot have expr with no operands");
840 auto type = operandsIn.front().getType();
841 assert(llvm::all_of(operandsIn.drop_front(),
842 [&](
auto op) { return op.getType() == type; }));
844 SmallVector<TypedAttr, 4> operands(operandsIn.begin(), operandsIn.end());
897 return Base::get(operands[0].getContext(), opcode, operands, type);
900 Attribute ParamExprAttr::parse(AsmParser &p, Type type) {
903 p.emitError(p.getNameLoc(),
"#hw.param.expr should have opcode suffix");
910 DialectAsmParser &p, Type type) {
911 SmallVector<TypedAttr> operands;
912 if (p.parseCommaSeparatedList(
913 mlir::AsmParser::Delimiter::LessGreater, [&]() -> ParseResult {
914 operands.push_back({});
915 return p.parseAttribute(operands.back(), type);
919 std::optional<PEO> opcode = symbolizePEO(opcodeStr);
920 if (!opcode.has_value()) {
921 p.emitError(p.getNameLoc(),
"unknown parameter expr operator name");
928 void ParamExprAttr::print(AsmPrinter &p)
const {
929 p <<
"." << stringifyPEO(getOpcode()) <<
'<';
930 llvm::interleaveComma(getOperands(), p.getStream(),
931 [&](Attribute op) { p.printAttributeWithoutType(op); });
935 // Replaces any ParamDeclRefAttr within a parametric expression with its
936 // corresponding value from the map of provided parameters.
937 static FailureOr<Attribute>
938 replaceDeclRefInExpr(Location loc,
939 const std::map<std::string, Attribute> ¶meters,
940 Attribute paramAttr, bool emitErrors) {
941 if (dyn_cast<IntegerAttr>(paramAttr)) {
942 // Nothing to do, constant value.
945 if (auto paramRefAttr = dyn_cast<hw::ParamDeclRefAttr>(paramAttr)) {
946 // Get the value from the provided parameters.
947 auto it = parameters.find(paramRefAttr.getName().str());
948 if (it == parameters.end()) {
950 return emitError(loc)
951 << "Could not find parameter " << paramRefAttr.getName().str()
952 << " in the provided parameters for the expression!";
957 if (auto paramExprAttr = dyn_cast<hw::ParamExprAttr>(paramAttr)) {
958 // Recurse into all operands of the expression.
959 llvm::SmallVector<TypedAttr, 4> replacedOperands;
960 for (auto operand : paramExprAttr.getOperands()) {
961 auto res = replaceDeclRefInExpr(loc, parameters, operand, emitErrors);
964 replacedOperands.push_back(res->cast<TypedAttr>());
967 hw::ParamExprAttr::get(paramExprAttr.getOpcode(), replacedOperands)};
969 llvm_unreachable("Unhandled parametric attribute");
973 FailureOr<TypedAttr> hw::evaluateParametricAttr(Location loc,
974 ArrayAttr parameters,
977 // Create a map of the provided parameters for faster lookup.
978 std::map<std::string, Attribute> parameterMap;
979 for (auto param : parameters) {
980 auto paramDecl = cast<ParamDeclAttr>(param);
981 parameterMap[paramDecl.getName().str()] = paramDecl.getValue();
984 // First, replace any ParamDeclRefAttr in the expression with its
985 // corresponding value in 'parameters
'.
987 replaceDeclRefInExpr(loc, parameterMap, paramAttr, emitErrors);
988 if (failed(paramAttrRes))
990 paramAttr = *paramAttrRes;
992 // Then, evaluate the parametric attribute.
993 if (isa<IntegerAttr, hw::ParamDeclRefAttr>(paramAttr))
994 return cast<TypedAttr>(paramAttr);
995 if (auto paramExprAttr = dyn_cast<hw::ParamExprAttr>(paramAttr)) {
996 // Since any ParamDeclRefAttr was replaced within the expression,
997 // we re-evaluate the expression through the existing ParamExprAttr
999 return ParamExprAttr::get(paramExprAttr.getOpcode(),
1000 paramExprAttr.getOperands());
1003 llvm_unreachable("Unhandled parametric attribute");
1007 template <typename TArray>
1008 FailureOr<Type> evaluateParametricArrayType(Location loc, ArrayAttr parameters,
1009 TArray arrayType, bool emitErrors) {
1010 auto size = evaluateParametricAttr(loc, parameters, arrayType.getSizeAttr(),
1014 auto elementType = evaluateParametricType(
1015 loc, parameters, arrayType.getElementType(), emitErrors);
1016 if (failed(elementType))
1019 // If the size was evaluated to a constant, use a 64-bit integer
1020 // attribute version of it
1021 if (auto intAttr = dyn_cast<IntegerAttr>(*size))
1023 arrayType.getContext(), *elementType,
1024 IntegerAttr::get(IntegerType::get(arrayType.getContext(), 64),
1025 intAttr.getValue().getSExtValue()));
1027 // Otherwise parameter references are still involved
1028 return TArray::get(arrayType.getContext(), *elementType, *size);
1031 FailureOr<Type> hw::evaluateParametricType(Location loc, ArrayAttr parameters,
1032 Type type, bool emitErrors) {
1033 return llvm::TypeSwitch<Type, FailureOr<Type>>(type)
1034 .Case<hw::IntType>([&](hw::IntType t) -> FailureOr<Type> {
1035 auto evaluatedWidth =
1036 evaluateParametricAttr(loc, parameters, t.getWidth(), emitErrors);
1037 if (failed(evaluatedWidth))
1040 // If the width was evaluated to a constant, return an `IntegerType`
1041 if (auto intAttr = evaluatedWidth->dyn_cast<IntegerAttr>())
1042 return {IntegerType::get(type.getContext(),
1043 intAttr.getValue().getSExtValue())};
1045 // Otherwise parameter references are still involved
1046 return hw::IntType::get(evaluatedWidth->cast<TypedAttr>());
1048 .Case<hw::ArrayType, hw::UnpackedArrayType>(
1049 [&](auto arrayType) -> FailureOr<Type> {
1050 return evaluateParametricArrayType(loc, parameters, arrayType,
1053 .Default([&](auto) { return type; });
1056 // Returns true if any part of this parametric attribute contains a reference
1057 // to a parameter declaration.
1058 static bool isParamAttrWithParamRef(Attribute expr) {
1059 return llvm::TypeSwitch<Attribute, bool>(expr)
1060 .Case([](ParamExprAttr attr) {
1061 return llvm::any_of(attr.getOperands(), isParamAttrWithParamRef);
1063 .Case([](ParamDeclRefAttr) { return true; })
1064 .Default([](auto) { return false; });
1067 bool hw::isParametricType(mlir::Type t) {
1068 return llvm::TypeSwitch<Type, bool>(t)
1070 [&](hw::IntType t) { return isParamAttrWithParamRef(t.getWidth()); })
1071 .Case<hw::ArrayType, hw::UnpackedArrayType>([&](auto arrayType) {
1072 return isParametricType(arrayType.getElementType()) ||
1073 isParamAttrWithParamRef(arrayType.getSizeAttr());
1075 .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.
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.