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();
259 Type outputFlagType) {
262 <<
" " << threshold.getInt();
266 setNameFn(getOutput(),
"out");
267 setNameFn(getEmpty(),
"empty");
268 setNameFn(getFull(),
"full");
269 if (
auto ae = getAlmostEmpty())
270 setNameFn(ae,
"almostEmpty");
271 if (
auto af = getAlmostFull())
272 setNameFn(af,
"almostFull");
276 auto aet = getAlmostEmptyThreshold();
277 auto aft = getAlmostFullThreshold();
278 size_t depth = getDepth();
279 if (aft.has_value() && aft.value() > depth)
280 return emitOpError(
"almost full threshold must be <= FIFO depth");
282 if (aet.has_value() && aet.value() > depth)
283 return emitOpError(
"almost empty threshold must be <= FIFO depth");
297 setNameFn(getResult(), *name);
301 if ((getReset() ==
nullptr) ^ (getResetValue() ==
nullptr))
303 "either reset and resetValue or neither must be specified");
307 std::optional<size_t> CompRegOp::getTargetResultIndex() {
return 0; }
309 template <
typename TOp>
311 if ((op.getReset() ==
nullptr) ^ (op.getResetValue() ==
nullptr))
312 return op->emitOpError(
313 "either reset and resetValue or neither must be specified");
314 bool hasReset = op.getReset() !=
nullptr;
315 if (hasReset && op.getResetValue().getType() != op.getInput().getType())
316 return op->emitOpError(
"reset value must be the same type as the input");
326 setNameFn(getResult(), *name);
329 std::optional<size_t> CompRegClockEnabledOp::getTargetResultIndex() {
346 setNameFn(getResult(), *name);
349 std::optional<size_t> ShiftRegOp::getTargetResultIndex() {
return 0; }
361 void FirRegOp::build(OpBuilder &builder, OperationState &result, Value input,
362 Value clk, StringAttr name, hw::InnerSymAttr innerSym,
365 OpBuilder::InsertionGuard guard(builder);
367 result.addOperands(input);
368 result.addOperands(clk);
370 result.addAttribute(getNameAttrName(result.name), name);
373 result.addAttribute(getInnerSymAttrName(result.name), innerSym);
376 result.addAttribute(getPresetAttrName(result.name), preset);
378 result.addTypes(input.getType());
381 void FirRegOp::build(OpBuilder &builder, OperationState &result, Value input,
382 Value clk, StringAttr name, Value reset, Value resetValue,
383 hw::InnerSymAttr innerSym,
bool isAsync) {
385 OpBuilder::InsertionGuard guard(builder);
387 result.addOperands(input);
388 result.addOperands(clk);
389 result.addOperands(reset);
390 result.addOperands(resetValue);
392 result.addAttribute(getNameAttrName(result.name), name);
394 result.addAttribute(getIsAsyncAttrName(result.name), builder.getUnitAttr());
397 result.addAttribute(getInnerSymAttrName(result.name), innerSym);
399 result.addTypes(input.getType());
402 ParseResult FirRegOp::parse(OpAsmParser &parser, OperationState &result) {
403 auto &builder = parser.getBuilder();
404 llvm::SMLoc loc = parser.getCurrentLocation();
406 using Op = OpAsmParser::UnresolvedOperand;
409 if (parser.parseOperand(next) || parser.parseKeyword(
"clock") ||
410 parser.parseOperand(clk))
413 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
414 hw::InnerSymAttr innerSym;
415 if (parser.parseCustomAttributeWithFallback(innerSym,
nullptr,
416 "inner_sym", result.attributes))
421 std::optional<std::pair<Op, Op>> resetAndValue;
422 if (succeeded(parser.parseOptionalKeyword(
"reset"))) {
424 if (succeeded(parser.parseOptionalKeyword(
"async")))
426 else if (succeeded(parser.parseOptionalKeyword(
"sync")))
429 return parser.emitError(loc,
"invalid reset, expected 'sync' or 'async'");
431 result.attributes.append(
"isAsync", builder.getUnitAttr());
433 resetAndValue = {{}, {}};
434 if (parser.parseOperand(resetAndValue->first) || parser.parseComma() ||
435 parser.parseOperand(resetAndValue->second))
439 std::optional<APInt> presetValue;
440 llvm::SMLoc presetValueLoc;
441 if (succeeded(parser.parseOptionalKeyword(
"preset"))) {
442 presetValueLoc = parser.getCurrentLocation();
443 OptionalParseResult presetIntResult =
444 parser.parseOptionalInteger(presetValue.emplace());
445 if (!presetIntResult.has_value() || failed(*presetIntResult))
446 return parser.emitError(loc,
"expected integer value");
450 if (parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
451 parser.parseType(ty))
453 result.addTypes({ty});
457 if (hw::type_isa<seq::ClockType>(ty)) {
462 return parser.emitError(presetValueLoc,
463 "cannot preset register of unknown width");
467 APInt presetResult = presetValue->sextOrTrunc(
width);
468 if (presetResult.zextOrTrunc(presetValue->getBitWidth()) != *presetValue)
469 return parser.emitError(loc,
"preset value too large");
471 auto builder = parser.getBuilder();
472 auto presetTy = builder.getIntegerType(
width);
473 auto resultAttr = builder.getIntegerAttr(presetTy, presetResult);
474 result.addAttribute(
"preset", resultAttr);
479 if (parser.resolveOperand(next, ty, result.operands))
483 if (parser.resolveOperand(clk, clkTy, result.operands))
488 if (parser.resolveOperand(resetAndValue->first, i1, result.operands) ||
489 parser.resolveOperand(resetAndValue->second, ty, result.operands))
496 void FirRegOp::print(::mlir::OpAsmPrinter &p) {
497 SmallVector<StringRef> elidedAttrs = {
498 getInnerSymAttrName(), getIsAsyncAttrName(), getPresetAttrName()};
500 p <<
' ' << getNext() <<
" clock " << getClk();
502 if (
auto sym = getInnerSymAttr()) {
508 p <<
" reset " << (getIsAsync() ?
"async" :
"sync") <<
' ';
509 p << getReset() <<
", " << getResetValue();
512 if (
auto preset = getPresetAttr()) {
513 p <<
" preset " << preset.getValue();
517 elidedAttrs.push_back(
"name");
519 p.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
520 p <<
" : " << getNext().getType();
525 if (getReset() || getResetValue() || getIsAsync()) {
526 if (!getReset() || !getResetValue())
527 return emitOpError(
"must specify reset and reset value");
530 return emitOpError(
"register with no reset cannot be async");
532 if (
auto preset = getPresetAttr()) {
535 if (preset.getType() != getType() && presetWidth !=
width)
536 return emitOpError(
"preset type width must match register type");
546 setNameFn(getResult(),
getName());
549 std::optional<size_t> FirRegOp::getTargetResultIndex() {
return 0; }
555 if (
auto reset = op.getReset()) {
557 if (constOp.getValue().isZero()) {
558 rewriter.replaceOpWithNewOp<FirRegOp>(
559 op, op.getNext(), op.getClk(), op.getNameAttr(),
560 op.getInnerSymAttr(), op.getPresetAttr());
567 if (op.getInnerSymAttr())
575 if (op.getNext() == op.getResult())
577 if (
auto clk = op.getClk().getDefiningOp<seq::ToClockOp>())
583 bool replaceWithConstZero =
true;
584 if (
auto preset = op.getPresetAttr())
585 if (!preset.getValue().isZero())
586 replaceWithConstZero =
false;
588 if (
isConstant() && !op.getResetValue() && replaceWithConstZero) {
589 if (isa<seq::ClockType>(op.getType())) {
590 rewriter.replaceOpWithNewOp<seq::ConstClockOp>(
595 rewriter.replaceOpWithNewOp<
hw::BitcastOp>(op, op.getType(), constant);
606 if (!op.getReset() && !op.getPresetAttr()) {
610 if (isa<IntegerType>(
611 hw::type_cast<hw::ArrayType>(op.getResult().getType())
612 .getElementType())) {
613 SmallVector<Value> nextOperands;
614 bool changed =
false;
615 for (
const auto &[i, value] :
616 llvm::enumerate(arrayCreate.getOperands())) {
617 auto index = arrayCreate.getOperands().size() - i - 1;
621 if (arrayGet.getInput() == op.getResult() &&
622 matchPattern(arrayGet.getIndex(),
623 m_ConstantInt(&elementIndex)) &&
624 elementIndex == index) {
631 nextOperands.push_back(value);
636 arrayCreate.getLoc(), nextOperands);
637 if (arrayCreate->hasOneUse())
640 rewriter.replaceOp(arrayCreate, newNextVal);
643 rewriter.replaceOpWithNewOp<FirRegOp>(op, newNextVal, op.getClk(),
645 op.getInnerSymAttr());
657 OpFoldResult FirRegOp::fold(FoldAdaptor adaptor) {
660 if (getInnerSymAttr())
663 auto presetAttr = getPresetAttr();
673 if (
auto reset = getReset())
675 if (constOp.getValue().isOne())
676 return getResetValue();
681 bool isTrivialFeedback = (getNext() == getResult());
682 bool isNeverClocked =
683 adaptor.getClk() !=
nullptr;
684 if (!isTrivialFeedback && !isNeverClocked)
689 if (
auto resetValue = getResetValue()) {
690 if (
auto *op = resetValue.getDefiningOp()) {
691 if (op->hasTrait<OpTrait::ConstantLike>() && !presetAttr)
693 if (
auto constOp = dyn_cast<hw::ConstantOp>(op))
694 if (presetAttr.getValue() == constOp.getValue())
702 auto intType = dyn_cast<IntegerType>(getType());
715 OpFoldResult ClockGateOp::fold(FoldAdaptor adaptor) {
727 if (
auto clockAttr = dyn_cast_or_null<ClockConstAttr>(adaptor.getInput()))
728 if (clockAttr.getValue() == ClockConst::Low)
733 auto clockGateInputOp = getInput().getDefiningOp<ClockGateOp>();
734 while (clockGateInputOp) {
735 if (clockGateInputOp.getEnable() == getEnable() &&
736 clockGateInputOp.getTestEnable() == getTestEnable())
738 clockGateInputOp = clockGateInputOp.getInput().getDefiningOp<ClockGateOp>();
745 PatternRewriter &rewriter) {
747 if (
auto testEnable = op.getTestEnable()) {
749 if (constOp.getValue().isZero()) {
750 rewriter.modifyOpInPlace(op,
751 [&] { op.getTestEnableMutable().clear(); });
760 std::optional<size_t> ClockGateOp::getTargetResultIndex() {
768 OpFoldResult ClockMuxOp::fold(FoldAdaptor adaptor) {
770 return getTrueClock();
772 return getFalseClock();
782 if (op.getInnerSymAttr())
786 for (
auto *user : op->getUsers()) {
787 if (isa<FirMemReadOp, FirMemReadWriteOp>(user))
789 assert(isa<FirMemWriteOp>(user) &&
"invalid seq.firmem user");
792 for (
auto *user : llvm::make_early_inc_range(op->getUsers()))
793 rewriter.eraseOp(user);
795 rewriter.eraseOp(op);
800 auto nameAttr = (*this)->getAttrOfType<StringAttr>(
"name");
801 if (!nameAttr.getValue().empty())
802 setNameFn(getResult(), nameAttr.getValue());
805 std::optional<size_t> FirMemOp::getTargetResultIndex() {
return 0; }
809 if (
auto mask = op.getMask()) {
810 auto memType = op.getMemory().getType();
811 if (!memType.getMaskWidth())
812 return op.emitOpError(
"has mask operand but memory type '")
813 << memType <<
"' has no mask";
815 if (mask.getType() != expected)
816 return op.emitOpError(
"has mask operand of type '")
817 << mask.getType() <<
"', but memory type requires '" << expected
829 return value.getDefiningOp<seq::ConstClockOp>();
835 return constOp.getValue().isZero();
842 return constOp.getValue().isAllOnes();
847 PatternRewriter &rewriter) {
850 rewriter.modifyOpInPlace(op, [&] { op.getEnableMutable().erase(0); });
857 PatternRewriter &rewriter) {
861 rewriter.eraseOp(op);
864 bool anyChanges =
false;
868 rewriter.modifyOpInPlace(op, [&] { op.getEnableMutable().erase(0); });
874 rewriter.modifyOpInPlace(op, [&] { op.getMaskMutable().erase(0); });
878 return success(anyChanges);
882 PatternRewriter &rewriter) {
887 auto opAttrs = op->getAttrs();
888 auto opAttrNames = op.getAttributeNames();
889 auto newOp = rewriter.replaceOpWithNewOp<FirMemReadOp>(
890 op, op.getMemory(), op.getAddress(), op.getClk(), op.getEnable());
891 for (
auto namedAttr : opAttrs)
892 if (!llvm::is_contained(opAttrNames, namedAttr.getName()))
893 newOp->setAttr(namedAttr.getName(), namedAttr.getValue());
896 bool anyChanges =
false;
900 rewriter.modifyOpInPlace(op, [&] { op.getEnableMutable().erase(0); });
906 rewriter.modifyOpInPlace(op, [&] { op.getMaskMutable().erase(0); });
910 return success(anyChanges);
917 OpFoldResult ConstClockOp::fold(FoldAdaptor adaptor) {
926 if (
auto fromClock = op.getInput().getDefiningOp<FromClockOp>()) {
927 rewriter.replaceOp(op, fromClock.getInput());
933 OpFoldResult ToClockOp::fold(FoldAdaptor adaptor) {
934 if (
auto fromClock = getInput().getDefiningOp<FromClockOp>())
935 return fromClock.getInput();
936 if (
auto intAttr = dyn_cast_or_null<IntegerAttr>(adaptor.getInput())) {
938 intAttr.getValue().isZero() ? ClockConst::Low : ClockConst::High;
945 PatternRewriter &rewriter) {
946 if (
auto toClock = op.getInput().getDefiningOp<ToClockOp>()) {
947 rewriter.replaceOp(op, toClock.getInput());
953 OpFoldResult FromClockOp::fold(FoldAdaptor adaptor) {
954 if (
auto toClock = getInput().getDefiningOp<ToClockOp>())
955 return toClock.getInput();
956 if (
auto clockAttr = dyn_cast_or_null<ClockConstAttr>(adaptor.getInput())) {
967 OpFoldResult ClockInverterOp::fold(FoldAdaptor adaptor) {
968 if (
auto chainedInv = getInput().getDefiningOp<ClockInverterOp>())
969 return chainedInv.getInput();
970 if (
auto clockAttr = dyn_cast_or_null<ClockConstAttr>(adaptor.getInput())) {
971 auto clockIn = clockAttr.getValue() == ClockConst::High;
973 clockIn ? ClockConst::Low : ClockConst::High);
982 FirMemory::FirMemory(hw::HWModuleGeneratedOp op) {
983 depth = op->getAttrOfType<IntegerAttr>(
"depth").
getInt();
984 numReadPorts = op->getAttrOfType<IntegerAttr>(
"numReadPorts").getUInt();
985 numWritePorts = op->getAttrOfType<IntegerAttr>(
"numWritePorts").getUInt();
987 op->getAttrOfType<IntegerAttr>(
"numReadWritePorts").getUInt();
988 readLatency = op->getAttrOfType<IntegerAttr>(
"readLatency").getUInt();
989 writeLatency = op->getAttrOfType<IntegerAttr>(
"writeLatency").getUInt();
990 dataWidth = op->getAttrOfType<IntegerAttr>(
"width").getUInt();
991 if (op->hasAttrOfType<IntegerAttr>(
"maskGran"))
992 maskGran = op->getAttrOfType<IntegerAttr>(
"maskGran").getUInt();
994 maskGran = dataWidth;
995 readUnderWrite = op->getAttrOfType<seq::RUWAttr>(
"readUnderWrite").getValue();
997 op->getAttrOfType<seq::WUWAttr>(
"writeUnderWrite").getValue();
998 if (
auto clockIDsAttr = op->getAttrOfType<ArrayAttr>(
"writeClockIDs"))
999 for (
auto clockID : clockIDsAttr)
1000 writeClockIDs.push_back(
1001 cast<IntegerAttr>(clockID).getValue().getZExtValue());
1002 initFilename = op->getAttrOfType<StringAttr>(
"initFilename").getValue();
1003 initIsBinary = op->getAttrOfType<BoolAttr>(
"initIsBinary").getValue();
1004 initIsInline = op->getAttrOfType<BoolAttr>(
"initIsInline").getValue();
1012 #define GET_OP_CLASSES
1013 #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)
static LogicalResult canonicalize(Op op, PatternRewriter &rewriter)
static LogicalResult verify(Value clock, bool eventExists, mlir::Location loc)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
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