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.startswith(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.endswith(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().endswith(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 FileListAttr FileListAttr::getFromFilename(MLIRContext *context,
178 const Twine &filename) {
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() <<
">";
282 LogicalResult InnerSymPropertiesAttr::verify(
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 &&
355 props[0].getSymVisibility().getValue().equals(
"public") &&
356 props[0].getFieldID() == 0) {
357 odsPrinter <<
"@" << props[0].getName().getValue();
360 auto names = props.vec();
362 std::sort(names.begin(), names.end(),
363 [&](InnerSymPropertiesAttr a, InnerSymPropertiesAttr b) {
364 return a.getFieldID() < b.getFieldID();
367 llvm::interleaveComma(names, odsPrinter, [&](InnerSymPropertiesAttr attr) {
368 attr.print(odsPrinter);
377 Attribute ParamDeclAttr::parse(AsmParser &p, Type trailing) {
384 if (p.parseLess() || p.parseString(&name) || p.parseColonType(type))
387 if (succeeded(p.parseOptionalEqual())) {
388 if (p.parseAttribute(
value, type))
392 if (p.parseGreater())
397 p.getBuilder().getStringAttr(name), type,
value);
401 void ParamDeclAttr::print(AsmPrinter &p)
const {
402 p <<
"<" <<
getName() <<
": " << getType();
405 p.printAttributeWithoutType(getValue());
414 Attribute ParamDeclRefAttr::parse(AsmParser &p, Type type) {
416 if (p.parseLess() || p.parseAttribute(name) || p.parseGreater() ||
417 (!type && (p.parseColon() || p.parseType(type))))
423 void ParamDeclRefAttr::print(AsmPrinter &p)
const {
431 Attribute ParamVerbatimAttr::parse(AsmParser &p, Type type) {
433 if (p.parseLess() || p.parseAttribute(text) || p.parseGreater() ||
434 (!type && (p.parseColon() || p.parseType(type))))
440 void ParamVerbatimAttr::print(AsmPrinter &p)
const {
441 p <<
"<" << getValue() <<
">";
451 ArrayRef<TypedAttr> operands,
452 llvm::function_ref<APInt(
const APInt &,
const APInt &)> calculate) {
453 assert(operands.size() == 2 &&
"binary operator always has two operands");
454 if (
auto lhs = operands[0].dyn_cast<IntegerAttr>())
455 if (
auto rhs = operands[1].dyn_cast<IntegerAttr>())
457 calculate(lhs.getValue(), rhs.getValue()));
465 llvm::function_ref<APInt(
const APInt &)> calculate) {
466 assert(operands.size() == 1 &&
"unary operator always has one operand");
467 if (
auto intAttr = operands[0].dyn_cast<IntegerAttr>())
475 if (
auto expr =
value.dyn_cast<ParamExprAttr>())
476 if (expr.getOpcode() == opcode)
494 if (rhs.isa<IntegerAttr>()) {
497 return !lhs.isa<IntegerAttr>();
499 if (lhs.isa<IntegerAttr>())
503 if (
auto rhsParam = rhs.dyn_cast<ParamDeclRefAttr>()) {
505 if (
auto lhsParam = lhs.dyn_cast<ParamDeclRefAttr>())
506 return lhsParam.getName().getValue() < rhsParam.getName().getValue();
510 if (lhs.isa<ParamDeclRefAttr>())
514 if (
auto rhsParam = rhs.dyn_cast<ParamVerbatimAttr>()) {
516 if (
auto lhsParam = lhs.dyn_cast<ParamVerbatimAttr>())
517 return lhsParam.getValue().getValue() < rhsParam.getValue().getValue();
521 if (lhs.isa<ParamVerbatimAttr>())
525 auto lhsExpr = lhs.cast<ParamExprAttr>(), rhsExpr = rhs.cast<ParamExprAttr>();
527 if (lhsExpr.getOpcode() != rhsExpr.getOpcode())
528 return stringifyPEO(lhsExpr.getOpcode()) <
529 stringifyPEO(rhsExpr.getOpcode());
532 ArrayRef<TypedAttr> lhsOperands = lhsExpr.getOperands(),
533 rhsOperands = rhsExpr.getOperands();
534 if (lhsOperands.size() != rhsOperands.size())
535 return lhsOperands.size() > rhsOperands.size();
539 for (
size_t i = 0, e = lhsOperands.size(); i != e; ++i) {
546 llvm_unreachable(
"expressions should never be equivalent");
554 PEO opcode, SmallVector<TypedAttr, 4> &operands,
555 llvm::function_ref<APInt(
const APInt &,
const APInt &)> calculateFn,
556 llvm::function_ref<
bool(
const APInt &)> identityConstantFn,
557 llvm::function_ref<
bool(
const APInt &)> destructiveConstantFn = {}) {
558 auto type = operands[0].getType();
560 if (operands.size() == 1)
565 for (
size_t i = 0, e = operands.size(); i != e; ++i) {
566 if (
auto subexpr =
dyn_castPE(opcode, operands[i])) {
567 std::swap(operands[i], operands.back());
571 operands.append(subexpr.getOperands().begin(),
572 subexpr.getOperands().end());
582 if (operands.back().isa<IntegerAttr>()) {
583 while (operands.size() >= 2 &&
584 operands[operands.size() - 2].isa<IntegerAttr>()) {
585 APInt c1 = operands.pop_back_val().cast<IntegerAttr>().getValue();
586 APInt c2 = operands.pop_back_val().cast<IntegerAttr>().getValue();
588 operands.push_back(resultConstant);
591 auto resultCst = operands.back().cast<IntegerAttr>();
595 if (destructiveConstantFn && destructiveConstantFn(resultCst.getValue()))
600 if (identityConstantFn(resultCst.getValue()) && operands.size() != 1)
604 return operands.size() == 1 ? operands[0] : TypedAttr();
613 if (
auto cst = mul.getOperands().back().dyn_cast<IntegerAttr>()) {
615 return {nonCst, cst};
617 return {operand, TypedAttr()};
624 static TypedAttr
simplifyAdd(SmallVector<TypedAttr, 4> &operands) {
626 PEO::Add, operands, [](
auto a,
auto b) {
return a + b; },
627 [](
auto cst) {
return cst.isZero(); }))
632 SmallVector<std::pair<TypedAttr, TypedAttr>> decomposedOperands;
633 llvm::SmallDenseSet<TypedAttr> nonConstantParts;
634 for (
auto &op : operands) {
641 if (!nonConstantParts.insert(decomposedOperands.back().first).second) {
643 TypedAttr mulOperand = decomposedOperands.back().first;
647 while (decomposedOperands[i].first != mulOperand)
650 operands.erase(operands.begin() + (&op - &operands[0]));
651 operands.erase(operands.begin() + i);
653 auto type = mulOperand.getType();
654 auto c1 = decomposedOperands[i].second,
655 c2 = decomposedOperands.back().second;
665 operands.push_back(mulCst);
673 static TypedAttr
simplifyMul(SmallVector<TypedAttr, 4> &operands) {
675 PEO::Mul, operands, [](
auto a,
auto b) {
return a * b; },
676 [](
auto cst) {
return cst.isOne(); },
677 [](
auto cst) {
return cst.isZero(); }))
682 for (
size_t i = 0, e = operands.size(); i != e; ++i) {
683 if (
auto subexpr =
dyn_castPE(PEO::Add, operands[i])) {
686 SmallVector<TypedAttr> mulOperands(operands.begin(), operands.end());
687 mulOperands.erase(mulOperands.begin() + i);
690 SmallVector<TypedAttr> addOperands;
691 for (
auto addOperand : subexpr.getOperands()) {
692 mulOperands.push_back(addOperand);
694 mulOperands.pop_back();
703 static TypedAttr
simplifyAnd(SmallVector<TypedAttr, 4> &operands) {
705 PEO::And, operands, [](
auto a,
auto b) {
return a & b; },
706 [](
auto cst) {
return cst.isAllOnes(); },
707 [](
auto cst) {
return cst.isZero(); });
710 static TypedAttr
simplifyOr(SmallVector<TypedAttr, 4> &operands) {
712 PEO::Or, operands, [](
auto a,
auto b) {
return a | b; },
713 [](
auto cst) {
return cst.isZero(); },
714 [](
auto cst) {
return cst.isAllOnes(); });
717 static TypedAttr
simplifyXor(SmallVector<TypedAttr, 4> &operands) {
719 PEO::Xor, operands, [](
auto a,
auto b) {
return a ^ b; },
720 [](
auto cst) {
return cst.isZero(); });
723 static TypedAttr
simplifyShl(SmallVector<TypedAttr, 4> &operands) {
726 if (
auto rhs = operands[1].dyn_cast<IntegerAttr>()) {
728 if (
auto lhs = operands[0].dyn_cast<IntegerAttr>())
730 lhs.getValue().shl(rhs.getValue()));
734 auto rhsCst = APInt::getOneBitSet(rhs.getValue().getBitWidth(),
735 rhs.getValue().getZExtValue());
745 if (
auto rhs = operands[1].dyn_cast<IntegerAttr>())
746 if (rhs.getValue().isZero())
749 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.lshr(b); });
755 if (
auto rhs = operands[1].dyn_cast<IntegerAttr>())
756 if (rhs.getValue().isZero())
759 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.ashr(b); });
765 if (
auto rhs = operands[1].dyn_cast<IntegerAttr>())
766 if (rhs.getValue().isOne())
769 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.udiv(b); });
775 if (
auto rhs = operands[1].dyn_cast<IntegerAttr>())
776 if (rhs.getValue().isOne())
779 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.sdiv(b); });
785 if (
auto rhs = operands[1].dyn_cast<IntegerAttr>())
786 if (rhs.getValue().isOne())
789 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.urem(b); });
795 if (
auto rhs = operands[1].dyn_cast<IntegerAttr>())
796 if (rhs.getValue().isOne())
799 return foldBinaryOp(operands, [](
auto a,
auto b) {
return a.srem(b); });
806 return APInt(a.getBitWidth(), a == 0 ? 0 : a.ceilLogBase2());
812 SmallVector<TypedAttr> newOperands;
813 SmallVector<StringAttr> stringsToCombine;
814 auto combineAndPush = [&]() {
815 if (stringsToCombine.empty())
818 SmallString<32> newString;
819 for (
auto part : stringsToCombine)
820 newString.append(part.getValue());
821 newOperands.push_back(
823 stringsToCombine.clear();
826 for (TypedAttr op : operands) {
827 if (
auto strOp = op.dyn_cast<StringAttr>()) {
829 stringsToCombine.push_back(strOp);
832 newOperands.push_back(op);
837 assert(!newOperands.empty());
838 if (newOperands.size() == 1)
839 return newOperands[0];
840 if (newOperands.size() < operands.size())
848 assert(!operandsIn.empty() &&
"Cannot have expr with no operands");
850 auto type = operandsIn.front().getType();
851 assert(llvm::all_of(operandsIn.drop_front(),
852 [&](
auto op) { return op.getType() == type; }));
854 SmallVector<TypedAttr, 4> operands(operandsIn.begin(), operandsIn.end());
907 return Base::get(operands[0].getContext(), opcode, operands, type);
910 Attribute ParamExprAttr::parse(AsmParser &p, Type type) {
913 p.emitError(p.getNameLoc(),
"#hw.param.expr should have opcode suffix");
920 DialectAsmParser &p, Type type) {
921 SmallVector<TypedAttr> operands;
922 if (p.parseCommaSeparatedList(
923 mlir::AsmParser::Delimiter::LessGreater, [&]() -> ParseResult {
924 operands.push_back({});
925 return p.parseAttribute(operands.back(), type);
929 std::optional<PEO> opcode = symbolizePEO(opcodeStr);
930 if (!opcode.has_value()) {
931 p.emitError(p.getNameLoc(),
"unknown parameter expr operator name");
938 void ParamExprAttr::print(AsmPrinter &p)
const {
939 p <<
"." << stringifyPEO(getOpcode()) <<
'<';
940 llvm::interleaveComma(getOperands(), p.getStream(),
941 [&](Attribute op) { p.printAttributeWithoutType(op); });
945 // Replaces any ParamDeclRefAttr within a parametric expression with its
946 // corresponding value from the map of provided parameters.
947 static FailureOr<Attribute>
948 replaceDeclRefInExpr(Location loc,
949 const std::map<std::string, Attribute> ¶meters,
950 Attribute paramAttr, bool emitErrors) {
951 if (paramAttr.dyn_cast<IntegerAttr>()) {
952 // Nothing to do, constant value.
955 if (auto paramRefAttr = paramAttr.dyn_cast<hw::ParamDeclRefAttr>()) {
956 // Get the value from the provided parameters.
957 auto it = parameters.find(paramRefAttr.getName().str());
958 if (it == parameters.end()) {
960 return emitError(loc)
961 << "Could not find parameter " << paramRefAttr.getName().str()
962 << " in the provided parameters for the expression!";
967 if (auto paramExprAttr = paramAttr.dyn_cast<hw::ParamExprAttr>()) {
968 // Recurse into all operands of the expression.
969 llvm::SmallVector<TypedAttr, 4> replacedOperands;
970 for (auto operand : paramExprAttr.getOperands()) {
971 auto res = replaceDeclRefInExpr(loc, parameters, operand, emitErrors);
974 replacedOperands.push_back(res->cast<TypedAttr>());
977 hw::ParamExprAttr::get(paramExprAttr.getOpcode(), replacedOperands)};
979 llvm_unreachable("Unhandled parametric attribute");
983 FailureOr<TypedAttr> hw::evaluateParametricAttr(Location loc,
984 ArrayAttr parameters,
987 // Create a map of the provided parameters for faster lookup.
988 std::map<std::string, Attribute> parameterMap;
989 for (auto param : parameters) {
990 auto paramDecl = param.cast<ParamDeclAttr>();
991 parameterMap[paramDecl.getName().str()] = paramDecl.getValue();
994 // First, replace any ParamDeclRefAttr in the expression with its
995 // corresponding value in 'parameters
'.
997 replaceDeclRefInExpr(loc, parameterMap, paramAttr, emitErrors);
998 if (failed(paramAttrRes))
1000 paramAttr = *paramAttrRes;
1002 // Then, evaluate the parametric attribute.
1003 if (paramAttr.isa<IntegerAttr, hw::ParamDeclRefAttr>())
1004 return paramAttr.cast<TypedAttr>();
1005 if (auto paramExprAttr = paramAttr.dyn_cast<hw::ParamExprAttr>()) {
1006 // Since any ParamDeclRefAttr was replaced within the expression,
1007 // we re-evaluate the expression through the existing ParamExprAttr
1009 return ParamExprAttr::get(paramExprAttr.getOpcode(),
1010 paramExprAttr.getOperands());
1013 llvm_unreachable("Unhandled parametric attribute");
1017 template <typename TArray>
1018 FailureOr<Type> evaluateParametricArrayType(Location loc, ArrayAttr parameters,
1019 TArray arrayType, bool emitErrors) {
1020 auto size = evaluateParametricAttr(loc, parameters, arrayType.getSizeAttr(),
1024 auto elementType = evaluateParametricType(
1025 loc, parameters, arrayType.getElementType(), emitErrors);
1026 if (failed(elementType))
1029 // If the size was evaluated to a constant, use a 64-bit integer
1030 // attribute version of it
1031 if (auto intAttr = size->template dyn_cast<IntegerAttr>())
1033 arrayType.getContext(), *elementType,
1034 IntegerAttr::get(IntegerType::get(arrayType.getContext(), 64),
1035 intAttr.getValue().getSExtValue()));
1037 // Otherwise parameter references are still involved
1038 return TArray::get(arrayType.getContext(), *elementType, *size);
1041 FailureOr<Type> hw::evaluateParametricType(Location loc, ArrayAttr parameters,
1042 Type type, bool emitErrors) {
1043 return llvm::TypeSwitch<Type, FailureOr<Type>>(type)
1044 .Case<hw::IntType>([&](hw::IntType t) -> FailureOr<Type> {
1045 auto evaluatedWidth =
1046 evaluateParametricAttr(loc, parameters, t.getWidth(), emitErrors);
1047 if (failed(evaluatedWidth))
1050 // If the width was evaluated to a constant, return an `IntegerType`
1051 if (auto intAttr = evaluatedWidth->dyn_cast<IntegerAttr>())
1052 return {IntegerType::get(type.getContext(),
1053 intAttr.getValue().getSExtValue())};
1055 // Otherwise parameter references are still involved
1056 return hw::IntType::get(evaluatedWidth->cast<TypedAttr>());
1058 .Case<hw::ArrayType, hw::UnpackedArrayType>(
1059 [&](auto arrayType) -> FailureOr<Type> {
1060 return evaluateParametricArrayType(loc, parameters, arrayType,
1063 .Default([&](auto) { return type; });
1066 // Returns true if any part of this parametric attribute contains a reference
1067 // to a parameter declaration.
1068 static bool isParamAttrWithParamRef(Attribute expr) {
1069 return llvm::TypeSwitch<Attribute, bool>(expr)
1070 .Case([](ParamExprAttr attr) {
1071 return llvm::any_of(attr.getOperands(), isParamAttrWithParamRef);
1073 .Case([](ParamDeclRefAttr) { return true; })
1074 .Default([](auto) { return false; });
1077 bool hw::isParametricType(mlir::Type t) {
1078 return llvm::TypeSwitch<Type, bool>(t)
1080 [&](hw::IntType t) { return isParamAttrWithParamRef(t.getWidth()); })
1081 .Case<hw::ArrayType, hw::UnpackedArrayType>([&](auto arrayType) {
1082 return isParametricType(arrayType.getElementType()) ||
1083 isParamAttrWithParamRef(arrayType.getSizeAttr());
1085 .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)
This file defines an intermediate representation for circuits acting as an abstraction for constraint...