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,
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.printSymbolName(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(); });
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");
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);
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; });
1080 return llvm::TypeSwitch<Type, bool>(t)
1083 .Case<hw::ArrayType, hw::UnpackedArrayType>([&](
auto arrayType) {
1087 .Default([](
auto) {
return false; });
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
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)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
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.
bool isHWEnumType(mlir::Type type)
Return true if the specified type is a HW Enum type.
mlir::Type getCanonicalType(mlir::Type type)
Recursively remove HW type aliases from a type and its subelements.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.