17 #include "mlir/IR/Builders.h"
18 #include "mlir/IR/DialectImplementation.h"
19 #include "mlir/IR/Matchers.h"
20 #include "mlir/IR/PatternMatch.h"
23 #include "llvm/ADT/SmallString.h"
26 using namespace circt;
30 auto memType = cast<seq::HLMemType>(hlmemHandle.getType());
31 auto shape = memType.getShape();
32 if (shape.size() != addresses.size())
35 for (
auto [dim, addr] : llvm::zip(shape, addresses)) {
36 auto addrType = dyn_cast<IntegerType>(addr.getType());
39 if (addrType.getIntOrFloatBitWidth() != llvm::Log2_64_Ceil(dim))
48 if (result.attributes.getNamed(
"name"))
52 StringRef resultName = parser.getResultName(0).first;
53 if (!resultName.empty() &&
isdigit(resultName[0]))
55 result.addAttribute(
"name", parser.getBuilder().getStringAttr(resultName));
59 if (!op->hasAttr(
"name"))
62 auto name = op->getAttrOfType<StringAttr>(
"name").getValue();
66 SmallString<32> resultNameStr;
67 llvm::raw_svector_ostream tmpStream(resultNameStr);
68 p.printOperand(op->getResult(0), tmpStream);
69 auto actualName = tmpStream.str().drop_front();
70 return actualName == name;
75 std::optional<OpAsmParser::UnresolvedOperand> operand,
83 Value operand, Type type) {
91 ParseResult ReadPortOp::parse(OpAsmParser &parser, OperationState &result) {
92 llvm::SMLoc loc = parser.getCurrentLocation();
94 OpAsmParser::UnresolvedOperand memOperand, rdenOperand;
96 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 2> addressOperands;
97 seq::HLMemType memType;
99 if (parser.parseOperand(memOperand) ||
100 parser.parseOperandList(addressOperands, OpAsmParser::Delimiter::Square))
103 if (succeeded(parser.parseOptionalKeyword(
"rden"))) {
104 if (failed(parser.parseOperand(rdenOperand)))
109 if (parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
110 parser.parseType(memType))
113 llvm::SmallVector<Type> operandTypes = memType.getAddressTypes();
114 operandTypes.insert(operandTypes.begin(), memType);
116 llvm::SmallVector<OpAsmParser::UnresolvedOperand> allOperands = {memOperand};
117 llvm::copy(addressOperands, std::back_inserter(allOperands));
119 operandTypes.push_back(parser.getBuilder().getI1Type());
120 allOperands.push_back(rdenOperand);
123 if (parser.resolveOperands(allOperands, operandTypes, loc, result.operands))
126 result.addTypes(memType.getElementType());
128 llvm::SmallVector<int32_t, 2> operandSizes;
129 operandSizes.push_back(1);
130 operandSizes.push_back(addressOperands.size());
131 operandSizes.push_back(hasRdEn ? 1 : 0);
132 result.addAttribute(
"operandSegmentSizes",
133 parser.getBuilder().getDenseI32ArrayAttr(operandSizes));
137 void ReadPortOp::print(OpAsmPrinter &p) {
138 p <<
" " << getMemory() <<
"[" << getAddresses() <<
"]";
140 p <<
" rden " << getRdEn();
141 p.printOptionalAttrDict((*this)->getAttrs(), {
"operandSegmentSizes"});
142 p <<
" : " << getMemory().getType();
146 auto memName = getMemory().getDefiningOp<seq::HLMemOp>().
getName();
147 setNameFn(getReadData(), (memName +
"_rdata").str());
150 void ReadPortOp::build(OpBuilder &
builder, OperationState &result, Value memory,
151 ValueRange addresses, Value rdEn,
unsigned latency) {
152 auto memType = cast<seq::HLMemType>(memory.getType());
153 ReadPortOp::build(
builder, result, memType.getElementType(), memory,
154 addresses, rdEn, latency);
161 ParseResult WritePortOp::parse(OpAsmParser &parser, OperationState &result) {
162 llvm::SMLoc loc = parser.getCurrentLocation();
163 OpAsmParser::UnresolvedOperand memOperand, dataOperand, wrenOperand;
164 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 2> addressOperands;
165 seq::HLMemType memType;
167 if (parser.parseOperand(memOperand) ||
168 parser.parseOperandList(addressOperands,
169 OpAsmParser::Delimiter::Square) ||
170 parser.parseOperand(dataOperand) || parser.parseKeyword(
"wren") ||
171 parser.parseOperand(wrenOperand) ||
172 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
173 parser.parseType(memType))
176 llvm::SmallVector<Type> operandTypes = memType.getAddressTypes();
177 operandTypes.insert(operandTypes.begin(), memType);
178 operandTypes.push_back(memType.getElementType());
179 operandTypes.push_back(parser.getBuilder().getI1Type());
181 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 2> allOperands(
183 allOperands.insert(allOperands.begin(), memOperand);
184 allOperands.push_back(dataOperand);
185 allOperands.push_back(wrenOperand);
187 if (parser.resolveOperands(allOperands, operandTypes, loc, result.operands))
193 void WritePortOp::print(OpAsmPrinter &p) {
194 p <<
" " << getMemory() <<
"[" << getAddresses() <<
"] " << getInData()
195 <<
" wren " << getWrEn();
196 p.printOptionalAttrDict((*this)->getAttrs());
197 p <<
" : " << getMemory().getType();
205 setNameFn(getHandle(),
getName());
208 void HLMemOp::build(OpBuilder &
builder, OperationState &result, Value clk,
209 Value rst, StringRef name, llvm::ArrayRef<int64_t> shape,
212 HLMemOp::build(
builder, result, t, clk, rst, name);
221 IntegerAttr &threshold,
222 Type &outputFlagType,
223 StringRef directive) {
225 if (succeeded(parser.parseOptionalKeyword(directive))) {
226 int64_t thresholdValue;
227 if (succeeded(parser.parseInteger(thresholdValue))) {
228 threshold = parser.getBuilder().getI64IntegerAttr(thresholdValue);
229 outputFlagType = parser.getBuilder().getI1Type();
232 return parser.emitError(parser.getNameLoc(),
233 "expected integer value after " + directive +
240 Type &outputFlagType) {
246 Type &outputFlagType) {
252 Type outputFlagType) {
255 <<
" " << threshold.getInt();
260 Type outputFlagType) {
263 <<
" " << threshold.getInt();
268 setNameFn(getOutput(),
"out");
269 setNameFn(getEmpty(),
"empty");
270 setNameFn(getFull(),
"full");
271 if (
auto ae = getAlmostEmpty())
272 setNameFn(ae,
"almostEmpty");
273 if (
auto af = getAlmostFull())
274 setNameFn(af,
"almostFull");
277 LogicalResult FIFOOp::verify() {
278 auto aet = getAlmostEmptyThreshold();
279 auto aft = getAlmostFullThreshold();
280 size_t depth = getDepth();
281 if (aft.has_value() && aft.value() > depth)
282 return emitOpError(
"almost full threshold must be <= FIFO depth");
284 if (aet.has_value() && aet.value() > depth)
285 return emitOpError(
"almost empty threshold must be <= FIFO depth");
299 setNameFn(getResult(), *name);
302 LogicalResult CompRegOp::verify() {
303 if ((getReset() ==
nullptr) ^ (getResetValue() ==
nullptr))
305 "either reset and resetValue or neither must be specified");
309 std::optional<size_t> CompRegOp::getTargetResultIndex() {
return 0; }
311 template <
typename TOp>
313 if ((op.getReset() ==
nullptr) ^ (op.getResetValue() ==
nullptr))
314 return op->emitOpError(
315 "either reset and resetValue or neither must be specified");
316 bool hasReset = op.getReset() !=
nullptr;
317 if (hasReset && op.getResetValue().getType() != op.getInput().getType())
318 return op->emitOpError(
"reset value must be the same type as the input");
328 setNameFn(getResult(), *name);
331 std::optional<size_t> CompRegClockEnabledOp::getTargetResultIndex() {
335 LogicalResult CompRegClockEnabledOp::verify() {
348 setNameFn(getResult(), *name);
351 std::optional<size_t> ShiftRegOp::getTargetResultIndex() {
return 0; }
353 LogicalResult ShiftRegOp::verify() {
363 void FirRegOp::build(OpBuilder &
builder, OperationState &result, Value input,
364 Value clk, StringAttr name, hw::InnerSymAttr innerSym) {
366 OpBuilder::InsertionGuard guard(
builder);
368 result.addOperands(input);
369 result.addOperands(clk);
371 result.addAttribute(getNameAttrName(result.name), name);
374 result.addAttribute(getInnerSymAttrName(result.name), innerSym);
376 result.addTypes(input.getType());
379 void FirRegOp::build(OpBuilder &
builder, OperationState &result, Value input,
380 Value clk, StringAttr name, Value reset, Value resetValue,
381 hw::InnerSymAttr innerSym,
bool isAsync) {
383 OpBuilder::InsertionGuard guard(
builder);
385 result.addOperands(input);
386 result.addOperands(clk);
387 result.addOperands(reset);
388 result.addOperands(resetValue);
390 result.addAttribute(getNameAttrName(result.name), name);
392 result.addAttribute(getIsAsyncAttrName(result.name),
builder.getUnitAttr());
395 result.addAttribute(getInnerSymAttrName(result.name), innerSym);
397 result.addTypes(input.getType());
400 ParseResult FirRegOp::parse(OpAsmParser &parser, OperationState &result) {
401 auto &
builder = parser.getBuilder();
402 llvm::SMLoc loc = parser.getCurrentLocation();
404 using Op = OpAsmParser::UnresolvedOperand;
407 if (parser.parseOperand(next) || parser.parseKeyword(
"clock") ||
408 parser.parseOperand(clk))
411 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
412 hw::InnerSymAttr innerSym;
413 if (parser.parseCustomAttributeWithFallback(innerSym,
nullptr,
414 "inner_sym", result.attributes))
419 std::optional<std::pair<Op, Op>> resetAndValue;
420 if (succeeded(parser.parseOptionalKeyword(
"reset"))) {
422 if (succeeded(parser.parseOptionalKeyword(
"async")))
424 else if (succeeded(parser.parseOptionalKeyword(
"sync")))
427 return parser.emitError(loc,
"invalid reset, expected 'sync' or 'async'");
429 result.attributes.append(
"isAsync",
builder.getUnitAttr());
431 resetAndValue = {{}, {}};
432 if (parser.parseOperand(resetAndValue->first) || parser.parseComma() ||
433 parser.parseOperand(resetAndValue->second))
437 std::optional<APInt> presetValue;
438 llvm::SMLoc presetValueLoc;
439 if (succeeded(parser.parseOptionalKeyword(
"preset"))) {
440 presetValueLoc = parser.getCurrentLocation();
441 OptionalParseResult presetIntResult =
442 parser.parseOptionalInteger(presetValue.emplace());
443 if (!presetIntResult.has_value() || failed(*presetIntResult))
444 return parser.emitError(loc,
"expected integer value");
448 if (parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
449 parser.parseType(ty))
451 result.addTypes({ty});
455 if (hw::type_isa<seq::ClockType>(ty)) {
460 return parser.emitError(presetValueLoc,
461 "cannot preset register of unknown width");
465 APInt presetResult = presetValue->sextOrTrunc(
width);
466 if (presetResult.zextOrTrunc(presetValue->getBitWidth()) != *presetValue)
467 return parser.emitError(loc,
"preset value too large");
469 auto builder = parser.getBuilder();
471 auto resultAttr =
builder.getIntegerAttr(presetTy, presetResult);
472 result.addAttribute(
"preset", resultAttr);
477 if (parser.resolveOperand(next, ty, result.operands))
481 if (parser.resolveOperand(clk, clkTy, result.operands))
486 if (parser.resolveOperand(resetAndValue->first, i1, result.operands) ||
487 parser.resolveOperand(resetAndValue->second, ty, result.operands))
494 void FirRegOp::print(::mlir::OpAsmPrinter &p) {
495 SmallVector<StringRef> elidedAttrs = {
496 getInnerSymAttrName(), getIsAsyncAttrName(), getPresetAttrName()};
498 p <<
' ' << getNext() <<
" clock " << getClk();
500 if (
auto sym = getInnerSymAttr()) {
506 p <<
" reset " << (getIsAsync() ?
"async" :
"sync") <<
' ';
507 p << getReset() <<
", " << getResetValue();
510 if (
auto preset = getPresetAttr()) {
511 p <<
" preset " << preset.getValue();
515 elidedAttrs.push_back(
"name");
517 p.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
518 p <<
" : " << getNext().getType();
522 LogicalResult FirRegOp::verify() {
523 if (getReset() || getResetValue() || getIsAsync()) {
524 if (!getReset() || !getResetValue())
525 return emitOpError(
"must specify reset and reset value");
528 return emitOpError(
"register with no reset cannot be async");
530 if (
auto preset = getPresetAttr()) {
533 if (preset.getType() != getType() && presetWidth !=
width)
534 return emitOpError(
"preset type width must match register type");
544 setNameFn(getResult(),
getName());
547 std::optional<size_t> FirRegOp::getTargetResultIndex() {
return 0; }
549 LogicalResult FirRegOp::canonicalize(FirRegOp op, PatternRewriter &rewriter) {
552 if (
auto reset = op.getReset()) {
554 if (constOp.getValue().isZero()) {
555 rewriter.replaceOpWithNewOp<FirRegOp>(op, op.getNext(), op.getClk(),
557 op.getInnerSymAttr());
564 if (op.getInnerSymAttr())
572 if (op.getNext() == op.getResult())
574 if (
auto clk = op.getClk().getDefiningOp<seq::ToClockOp>())
580 if (
auto resetValue = op.getResetValue()) {
582 rewriter.replaceOp(op, resetValue);
584 if (isa<seq::ClockType>(op.getType())) {
585 rewriter.replaceOpWithNewOp<seq::ConstClockOp>(
591 rewriter.replaceOpWithNewOp<
hw::BitcastOp>(op, op.getType(), constant);
603 if (!op.getReset()) {
607 if (isa<IntegerType>(
608 hw::type_cast<hw::ArrayType>(op.getResult().getType())
609 .getElementType())) {
610 SmallVector<Value> nextOperands;
611 bool changed =
false;
612 for (
const auto &[i, value] :
613 llvm::enumerate(arrayCreate.getOperands())) {
614 auto index = arrayCreate.getOperands().size() - i - 1;
618 if (arrayGet.getInput() == op.getResult() &&
619 matchPattern(arrayGet.getIndex(),
620 m_ConstantInt(&elementIndex)) &&
621 elementIndex == index) {
628 nextOperands.push_back(value);
633 arrayCreate.getLoc(), nextOperands);
634 if (arrayCreate->hasOneUse())
637 rewriter.replaceOp(arrayCreate, newNextVal);
640 rewriter.replaceOpWithNewOp<FirRegOp>(op, newNextVal, op.getClk(),
642 op.getInnerSymAttr());
654 OpFoldResult FirRegOp::fold(FoldAdaptor adaptor) {
656 if (getInnerSymAttr())
666 if (
auto reset = getReset())
668 if (constOp.getValue().isOne())
669 return getResetValue();
674 bool isTrivialFeedback = (getNext() == getResult());
675 bool isNeverClocked =
676 adaptor.getClk() !=
nullptr;
677 if (!isTrivialFeedback && !isNeverClocked)
681 if (
auto resetValue = getResetValue())
686 auto intType = dyn_cast<IntegerType>(getType());
696 OpFoldResult ClockGateOp::fold(FoldAdaptor adaptor) {
708 if (
auto clockAttr = dyn_cast_or_null<ClockConstAttr>(adaptor.getInput()))
709 if (clockAttr.getValue() == ClockConst::Low)
714 auto clockGateInputOp = getInput().getDefiningOp<ClockGateOp>();
715 while (clockGateInputOp) {
716 if (clockGateInputOp.getEnable() == getEnable() &&
717 clockGateInputOp.getTestEnable() == getTestEnable())
719 clockGateInputOp = clockGateInputOp.getInput().getDefiningOp<ClockGateOp>();
725 LogicalResult ClockGateOp::canonicalize(ClockGateOp op,
726 PatternRewriter &rewriter) {
728 if (
auto testEnable = op.getTestEnable()) {
730 if (constOp.getValue().isZero()) {
731 rewriter.modifyOpInPlace(op,
732 [&] { op.getTestEnableMutable().clear(); });
741 std::optional<size_t> ClockGateOp::getTargetResultIndex() {
749 OpFoldResult ClockMuxOp::fold(FoldAdaptor adaptor) {
751 return getTrueClock();
753 return getFalseClock();
761 LogicalResult FirMemOp::canonicalize(FirMemOp op, PatternRewriter &rewriter) {
763 if (op.getInnerSymAttr())
767 for (
auto *user : op->getUsers()) {
768 if (isa<FirMemReadOp, FirMemReadWriteOp>(user))
770 assert(isa<FirMemWriteOp>(user) &&
"invalid seq.firmem user");
773 for (
auto *user : llvm::make_early_inc_range(op->getUsers()))
774 rewriter.eraseOp(user);
776 rewriter.eraseOp(op);
781 auto nameAttr = (*this)->getAttrOfType<StringAttr>(
"name");
782 if (!nameAttr.getValue().empty())
783 setNameFn(getResult(), nameAttr.getValue());
786 std::optional<size_t> FirMemOp::getTargetResultIndex() {
return 0; }
790 if (
auto mask = op.getMask()) {
791 auto memType = op.getMemory().getType();
792 if (!memType.getMaskWidth())
793 return op.emitOpError(
"has mask operand but memory type '")
794 << memType <<
"' has no mask";
796 if (mask.getType() != expected)
797 return op.emitOpError(
"has mask operand of type '")
798 << mask.getType() <<
"', but memory type requires '" << expected
805 LogicalResult FirMemReadWriteOp::verify() {
return verifyFirMemMask(*
this); }
810 return value.getDefiningOp<seq::ConstClockOp>();
816 return constOp.getValue().isZero();
823 return constOp.getValue().isAllOnes();
827 LogicalResult FirMemReadOp::canonicalize(FirMemReadOp op,
828 PatternRewriter &rewriter) {
831 rewriter.modifyOpInPlace(op, [&] { op.getEnableMutable().erase(0); });
837 LogicalResult FirMemWriteOp::canonicalize(FirMemWriteOp op,
838 PatternRewriter &rewriter) {
842 rewriter.eraseOp(op);
845 bool anyChanges =
false;
849 rewriter.modifyOpInPlace(op, [&] { op.getEnableMutable().erase(0); });
855 rewriter.modifyOpInPlace(op, [&] { op.getMaskMutable().erase(0); });
859 return success(anyChanges);
862 LogicalResult FirMemReadWriteOp::canonicalize(FirMemReadWriteOp op,
863 PatternRewriter &rewriter) {
868 auto opAttrs = op->getAttrs();
869 auto opAttrNames = op.getAttributeNames();
870 auto newOp = rewriter.replaceOpWithNewOp<FirMemReadOp>(
871 op, op.getMemory(), op.getAddress(), op.getClk(), op.getEnable());
872 for (
auto namedAttr : opAttrs)
873 if (!llvm::is_contained(opAttrNames, namedAttr.getName()))
874 newOp->setAttr(namedAttr.getName(), namedAttr.getValue());
877 bool anyChanges =
false;
881 rewriter.modifyOpInPlace(op, [&] { op.getEnableMutable().erase(0); });
887 rewriter.modifyOpInPlace(op, [&] { op.getMaskMutable().erase(0); });
891 return success(anyChanges);
898 OpFoldResult ConstClockOp::fold(FoldAdaptor adaptor) {
906 LogicalResult ToClockOp::canonicalize(ToClockOp op, PatternRewriter &rewriter) {
907 if (
auto fromClock = op.getInput().getDefiningOp<FromClockOp>()) {
908 rewriter.replaceOp(op, fromClock.getInput());
914 OpFoldResult ToClockOp::fold(FoldAdaptor adaptor) {
915 if (
auto fromClock = getInput().getDefiningOp<FromClockOp>())
916 return fromClock.getInput();
917 if (
auto intAttr = dyn_cast_or_null<IntegerAttr>(adaptor.getInput())) {
919 intAttr.getValue().isZero() ? ClockConst::Low : ClockConst::High;
925 LogicalResult FromClockOp::canonicalize(FromClockOp op,
926 PatternRewriter &rewriter) {
927 if (
auto toClock = op.getInput().getDefiningOp<ToClockOp>()) {
928 rewriter.replaceOp(op, toClock.getInput());
934 OpFoldResult FromClockOp::fold(FoldAdaptor adaptor) {
935 if (
auto toClock = getInput().getDefiningOp<ToClockOp>())
936 return toClock.getInput();
937 if (
auto clockAttr = dyn_cast_or_null<ClockConstAttr>(adaptor.getInput())) {
948 OpFoldResult ClockInverterOp::fold(FoldAdaptor adaptor) {
949 if (
auto chainedInv = getInput().getDefiningOp<ClockInverterOp>())
950 return chainedInv.getInput();
951 if (
auto clockAttr = dyn_cast_or_null<ClockConstAttr>(adaptor.getInput())) {
952 auto clockIn = clockAttr.getValue() == ClockConst::High;
954 clockIn ? ClockConst::Low : ClockConst::High);
963 FirMemory::FirMemory(hw::HWModuleGeneratedOp op) {
964 depth = op->getAttrOfType<IntegerAttr>(
"depth").
getInt();
965 numReadPorts = op->getAttrOfType<IntegerAttr>(
"numReadPorts").getUInt();
966 numWritePorts = op->getAttrOfType<IntegerAttr>(
"numWritePorts").getUInt();
968 op->getAttrOfType<IntegerAttr>(
"numReadWritePorts").getUInt();
969 readLatency = op->getAttrOfType<IntegerAttr>(
"readLatency").getUInt();
970 writeLatency = op->getAttrOfType<IntegerAttr>(
"writeLatency").getUInt();
971 dataWidth = op->getAttrOfType<IntegerAttr>(
"width").getUInt();
972 if (op->hasAttrOfType<IntegerAttr>(
"maskGran"))
973 maskGran = op->getAttrOfType<IntegerAttr>(
"maskGran").getUInt();
975 maskGran = dataWidth;
976 readUnderWrite = op->getAttrOfType<seq::RUWAttr>(
"readUnderWrite").getValue();
978 op->getAttrOfType<seq::WUWAttr>(
"writeUnderWrite").getValue();
979 if (
auto clockIDsAttr = op->getAttrOfType<ArrayAttr>(
"writeClockIDs"))
980 for (
auto clockID : clockIDsAttr)
981 writeClockIDs.push_back(
982 cast<IntegerAttr>(clockID).getValue().getZExtValue());
983 initFilename = op->getAttrOfType<StringAttr>(
"initFilename").getValue();
984 initIsBinary = op->getAttrOfType<BoolAttr>(
"initIsBinary").getValue();
985 initIsInline = op->getAttrOfType<BoolAttr>(
"initIsInline").getValue();
993 #define GET_OP_CLASSES
994 #include "circt/Dialect/Seq/Seq.cpp.inc"
assert(baseType &&"element must be base type")
static bool isConstantOne(Attribute operand)
Determine whether a constant operand is a one value for the sake of constant folding.
static InstancePath empty
static std::optional< APInt > getInt(Value value)
Helper to convert a value to a constant integer if it is one.
void printFIFOAFThreshold(OpAsmPrinter &p, Operation *op, IntegerAttr threshold, Type outputFlagType)
static bool isConstClock(Value value)
static ParseResult parseFIFOFlagThreshold(OpAsmParser &parser, IntegerAttr &threshold, Type &outputFlagType, StringRef directive)
static void printOptionalTypeMatch(OpAsmPrinter &p, Operation *op, Type refType, Value operand, Type type)
static bool isConstAllOnes(Value value)
void printFIFOAEThreshold(OpAsmPrinter &p, Operation *op, IntegerAttr threshold, Type outputFlagType)
LogicalResult verifyResets(TOp op)
static bool canElideName(OpAsmPrinter &p, Operation *op)
ParseResult parseFIFOAEThreshold(OpAsmParser &parser, IntegerAttr &threshold, Type &outputFlagType)
static bool isConstZero(Value value)
static LogicalResult verifyFirMemMask(Op op)
static ParseResult parseOptionalTypeMatch(OpAsmParser &parser, Type refType, std::optional< OpAsmParser::UnresolvedOperand > operand, Type &type)
static void setNameFromResult(OpAsmParser &parser, OperationState &result)
ParseResult parseFIFOAFThreshold(OpAsmParser &parser, IntegerAttr &threshold, Type &outputFlagType)
def create(data_type, value)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
bool isConstant(Operation *op)
Return true if the specified operation has a constant value.
std::optional< int64_t > getBitWidth(FIRRTLBaseType type, bool ignoreFlip=false)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
void getAsmResultNames(OpAsmSetValueNameFn setNameFn, StringRef instanceName, ArrayAttr resultNames, ValueRange results)
Suggest a name for each result value based on the saved result names attribute.
bool isValidIndexValues(Value hlmemHandle, ValueRange addresses)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
static bool isConstantZero(Attribute operand)
Determine whether a constant operand is a zero value.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn