16 #include "mlir/Dialect/CommonFolders.h"
17 #include "mlir/IR/Attributes.h"
18 #include "mlir/IR/BuiltinOps.h"
19 #include "mlir/IR/BuiltinTypes.h"
20 #include "mlir/IR/Matchers.h"
21 #include "mlir/IR/OpImplementation.h"
22 #include "mlir/IR/PatternMatch.h"
23 #include "mlir/IR/Region.h"
24 #include "mlir/IR/Types.h"
25 #include "mlir/IR/Value.h"
26 #include "mlir/Support/LogicalResult.h"
27 #include "llvm/ADT/ArrayRef.h"
28 #include "llvm/ADT/SmallVector.h"
29 #include "llvm/ADT/StringSet.h"
30 #include "llvm/ADT/TypeSwitch.h"
32 using namespace circt;
35 template <
class AttrElementT,
36 class ElementValueT =
typename AttrElementT::ValueType,
37 class CalculationT = function_ref<ElementValueT(ElementValueT)>>
39 const CalculationT &calculate) {
40 assert(operands.size() == 1 &&
"unary op takes one operand");
44 if (
auto val = dyn_cast<AttrElementT>(operands[0])) {
46 }
else if (
auto val = dyn_cast<SplatElementsAttr>(operands[0])) {
49 auto elementResult = calculate(val.getSplatValue<ElementValueT>());
52 if (
auto val = dyn_cast<ElementsAttr>(operands[0])) {
55 auto valIt = val.getValues<ElementValueT>().begin();
56 SmallVector<ElementValueT, 4> elementResults;
57 elementResults.reserve(val.getNumElements());
58 for (
size_t i = 0, e = val.getNumElements(); i < e; ++i, ++valIt)
59 elementResults.push_back(calculate(*valIt));
65 template <
class AttrElementT,
66 class ElementValueT =
typename AttrElementT::ValueType,
67 class CalculationT = function_ref<
68 ElementValueT(ElementValueT, ElementValueT, ElementValueT)>>
70 const CalculationT &calculate) {
71 assert(operands.size() == 3 &&
"ternary op takes three operands");
72 if (!operands[0] || !operands[1] || !operands[2])
75 if (isa<AttrElementT>(operands[0]) && isa<AttrElementT>(operands[1]) &&
76 isa<AttrElementT>(operands[2])) {
77 auto fst = cast<AttrElementT>(operands[0]);
78 auto snd = cast<AttrElementT>(operands[1]);
79 auto trd = cast<AttrElementT>(operands[2]);
83 calculate(fst.getValue(), snd.getValue(), trd.getValue()));
85 if (isa<SplatElementsAttr>(operands[0]) &&
86 isa<SplatElementsAttr>(operands[1]) &&
87 isa<SplatElementsAttr>(operands[2])) {
90 auto fst = cast<SplatElementsAttr>(operands[0]);
91 auto snd = cast<SplatElementsAttr>(operands[1]);
92 auto trd = cast<SplatElementsAttr>(operands[2]);
94 auto elementResult = calculate(fst.getSplatValue<ElementValueT>(),
95 snd.getSplatValue<ElementValueT>(),
96 trd.getSplatValue<ElementValueT>());
99 if (isa<ElementsAttr>(operands[0]) && isa<ElementsAttr>(operands[1]) &&
100 isa<ElementsAttr>(operands[2])) {
103 auto fst = cast<ElementsAttr>(operands[0]);
104 auto snd = cast<ElementsAttr>(operands[1]);
105 auto trd = cast<ElementsAttr>(operands[2]);
107 auto fstIt = fst.getValues<ElementValueT>().begin();
108 auto sndIt = snd.getValues<ElementValueT>().begin();
109 auto trdIt = trd.getValues<ElementValueT>().begin();
110 SmallVector<ElementValueT, 4> elementResults;
111 elementResults.reserve(fst.getNumElements());
112 for (
size_t i = 0, e = fst.getNumElements(); i < e;
113 ++i, ++fstIt, ++sndIt, ++trdIt)
114 elementResults.push_back(calculate(*fstIt, *sndIt, *trdIt));
122 struct constant_int_all_ones_matcher {
123 bool match(Operation *op) {
125 return mlir::detail::constant_int_value_binder(&value).match(op) &&
133 if (
auto sig = dyn_cast<llhd::SigType>(type))
134 type = sig.getUnderlyingType();
135 else if (
auto ptr = dyn_cast<llhd::PtrType>(type))
136 type = ptr.getUnderlyingType();
137 if (
auto array = dyn_cast<hw::ArrayType>(type))
138 return array.getNumElements();
139 if (
auto tup = dyn_cast<hw::StructType>(type))
140 return tup.getElements().size();
141 return type.getIntOrFloatBitWidth();
145 if (
auto sig = dyn_cast<llhd::SigType>(type))
146 type = sig.getUnderlyingType();
147 else if (
auto ptr = dyn_cast<llhd::PtrType>(type))
148 type = ptr.getUnderlyingType();
149 if (
auto array = dyn_cast<hw::ArrayType>(type))
150 return array.getElementType();
162 OpFoldResult llhd::ConstantTimeOp::fold(FoldAdaptor adaptor) {
163 assert(adaptor.getOperands().empty() &&
"const has no operands");
164 return getValueAttr();
167 void llhd::ConstantTimeOp::build(OpBuilder &
builder, OperationState &result,
168 unsigned time,
const StringRef &timeUnit,
169 unsigned delta,
unsigned epsilon) {
170 auto *ctx =
builder.getContext();
171 auto attr =
TimeAttr::get(ctx, time, timeUnit, delta, epsilon);
186 if (op.getResultWidth() == op.getInputWidth() &&
187 cast<IntegerAttr>(operands[1]).getValue().isZero())
188 return op.getInput();
193 OpFoldResult llhd::SigExtractOp::fold(FoldAdaptor adaptor) {
197 OpFoldResult llhd::PtrExtractOp::fold(FoldAdaptor adaptor) {
207 ArrayRef<Attribute> operands) {
212 if (op.getResultWidth() == op.getInputWidth() &&
213 cast<IntegerAttr>(operands[1]).getValue().isZero())
214 return op.getInput();
219 OpFoldResult llhd::SigArraySliceOp::fold(FoldAdaptor adaptor) {
223 OpFoldResult llhd::PtrArraySliceOp::fold(FoldAdaptor adaptor) {
229 PatternRewriter &rewriter) {
230 IntegerAttr indexAttr;
231 if (!matchPattern(op.getLowIndex(), m_Constant(&indexAttr)))
237 if (matchPattern(op.getInput(),
238 m_Op<Op>(matchers::m_Any(), m_Constant(&a)))) {
239 auto sliceOp = op.getInput().template getDefiningOp<Op>();
240 op.getInputMutable().assign(sliceOp.getInput());
242 op->getLoc(), a.getValue() + indexAttr.getValue());
243 op.getLowIndexMutable().assign(newIndex);
251 LogicalResult llhd::SigArraySliceOp::canonicalize(llhd::SigArraySliceOp op,
252 PatternRewriter &rewriter) {
256 LogicalResult llhd::PtrArraySliceOp::canonicalize(llhd::PtrArraySliceOp op,
257 PatternRewriter &rewriter) {
265 template <
class SigPtrType>
267 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
268 DictionaryAttr attrs, mlir::OpaqueProperties properties,
269 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
271 cast<hw::StructType>(
272 cast<SigPtrType>(operands[0].getType()).getUnderlyingType())
274 cast<StringAttr>(attrs.getNamed(
"field")->getValue()).getValue());
276 context->getDiagEngine().emit(loc.value_or(UnknownLoc()),
277 DiagnosticSeverity::Error)
278 <<
"invalid field name specified";
286 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
287 DictionaryAttr attrs, mlir::OpaqueProperties properties,
288 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
289 return inferReturnTypesOfStructExtractOp<llhd::SigType>(
290 context, loc, operands, attrs, properties, regions, results);
294 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
295 DictionaryAttr attrs, mlir::OpaqueProperties properties,
296 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
297 return inferReturnTypesOfStructExtractOp<llhd::PtrType>(
298 context, loc, operands, attrs, properties, regions, results);
305 LogicalResult llhd::DrvOp::fold(FoldAdaptor adaptor,
306 SmallVectorImpl<OpFoldResult> &result) {
310 if (matchPattern(getEnable(), m_One())) {
311 getEnableMutable().clear();
318 LogicalResult llhd::DrvOp::canonicalize(llhd::DrvOp op,
319 PatternRewriter &rewriter) {
323 if (matchPattern(op.getEnable(), m_Zero())) {
324 rewriter.eraseOp(op);
336 SuccessorOperands llhd::WaitOp::getSuccessorOperands(
unsigned index) {
337 assert(index == 0 &&
"invalid successor index");
338 return SuccessorOperands(getDestOpsMutable());
350 SmallVectorImpl<OpAsmParser::Argument> &args,
351 SmallVectorImpl<Type> &argTypes) {
352 auto parseElt = [&]() -> ParseResult {
353 OpAsmParser::Argument argument;
355 auto optArg = parser.parseOptionalArgument(argument);
356 if (optArg.has_value()) {
357 if (succeeded(optArg.value())) {
358 if (!argument.ssaName.name.empty() &&
359 succeeded(parser.parseColonType(argType))) {
360 args.push_back(argument);
361 argTypes.push_back(argType);
362 args.back().type = argType;
369 return parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
377 SmallVectorImpl<OpAsmParser::Argument> &args,
378 SmallVectorImpl<Type> &argTypes) {
382 IntegerAttr insAttr = parser.getBuilder().getI64IntegerAttr(args.size());
383 result.addAttribute(
"ins", insAttr);
384 if (succeeded(parser.parseOptionalArrow()))
391 ParseResult llhd::EntityOp::parse(OpAsmParser &parser, OperationState &result) {
392 StringAttr entityName;
393 SmallVector<OpAsmParser::Argument, 4> args;
394 SmallVector<Type, 4> argTypes;
396 if (parser.parseSymbolName(entityName, SymbolTable::getSymbolAttrName(),
403 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
406 auto type = parser.getBuilder().getFunctionType(argTypes, std::nullopt);
408 circt::llhd::EntityOp::getFunctionTypeAttrName(result.name),
411 auto &body = *result.addRegion();
412 if (parser.parseRegion(body, args))
415 body.push_back(std::make_unique<Block>().release());
421 std::vector<BlockArgument> args) {
423 llvm::interleaveComma(args, printer, [&](BlockArgument arg) {
424 printer << arg <<
" : " << arg.getType();
429 void llhd::EntityOp::print(OpAsmPrinter &printer) {
430 std::vector<BlockArgument> ins, outs;
431 uint64_t nIns = getInsAttr().getInt();
432 for (uint64_t i = 0; i < getBody().front().getArguments().size(); ++i) {
436 ins.push_back(getBody().front().getArguments()[i]);
438 outs.push_back(getBody().front().getArguments()[i]);
443 ->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName())
446 printer.printSymbolName(entityName);
451 printer.printOptionalAttrDictWithKeyword(
453 {SymbolTable::getSymbolAttrName(),
454 getFunctionTypeAttrName(),
"ins"});
456 printer.printRegion(getBody(),
false,
false);
459 LogicalResult llhd::EntityOp::verify() {
460 uint64_t numArgs = getNumArguments();
461 uint64_t nIns = getInsAttr().getInt();
463 if (numArgs < nIns) {
465 "Cannot have more inputs than arguments, expected at most ")
466 << numArgs <<
" but got: " << nIns;
470 for (
size_t i = 0; i < numArgs; ++i)
471 if (!isa<llhd::SigType>(getArgument(i).getType()))
472 return emitError(
"usage of invalid argument type. Got ")
473 << getArgument(i).getType() <<
", expected LLHD signal type";
478 LogicalResult circt::llhd::EntityOp::verifyType() {
479 FunctionType type = getFunctionType();
483 if (type.getNumResults() > 0)
484 return emitOpError(
"an entity cannot have return types.");
487 for (Type inputType : type.getInputs())
488 if (!isa<llhd::SigType>(inputType))
489 return emitOpError(
"usage of invalid argument type. Got ")
490 << inputType <<
", expected LLHD signal type";
495 LogicalResult circt::llhd::EntityOp::verifyBody() {
497 llvm::StringSet<> sigSet;
498 llvm::StringSet<> instSet;
499 auto walkResult = walk([&sigSet, &instSet](Operation *op) -> WalkResult {
500 return TypeSwitch<Operation *, WalkResult>(op)
501 .Case<SigOp>([&](
auto sigOp) -> WalkResult {
502 if (!sigSet.insert(sigOp.getName()).second)
503 return sigOp.emitError(
"redefinition of signal named '")
504 << sigOp.getName() <<
"'!";
508 .Case<OutputOp>([&](
auto outputOp) -> WalkResult {
509 if (outputOp.getName() && !sigSet.insert(*outputOp.getName()).second)
510 return outputOp.emitError(
"redefinition of signal named '")
511 << *outputOp.getName() <<
"'!";
515 .Case<InstOp>([&](
auto instOp) -> WalkResult {
516 if (!instSet.insert(instOp.getName()).second)
517 return instOp.emitError(
"redefinition of instance named '")
518 << instOp.getName() <<
"'!";
522 .Default([](
auto op) -> WalkResult {
return WalkResult::advance(); });
525 return failure(walkResult.wasInterrupted());
529 ArrayRef<Type> llhd::EntityOp::getArgumentTypes() {
530 return getFunctionType().getInputs();
534 ArrayRef<Type> llhd::EntityOp::getResultTypes() {
535 return getFunctionType().getResults();
538 Region *llhd::EntityOp::getCallableRegion() {
539 return isExternal() ? nullptr : &getBody();
546 LogicalResult circt::llhd::ProcOp::verifyType() {
549 if (getNumResults() > 0) {
551 "process has more than zero return types, this is not allowed");
555 for (
int i = 0, e = getNumArguments(); i < e; ++i) {
556 if (!isa<llhd::SigType>(getArgument(i).getType())) {
557 return emitOpError(
"usage of invalid argument type, was ")
558 << getArgument(i).getType() <<
", expected LLHD signal type";
565 ArrayRef<Type> llhd::ProcOp::getArgumentTypes() {
566 return getFunctionType().getInputs();
570 ArrayRef<Type> llhd::ProcOp::getResultTypes() {
571 return getFunctionType().getResults();
574 LogicalResult circt::llhd::ProcOp::verifyBody() {
return success(); }
576 LogicalResult llhd::ProcOp::verify() {
579 uint64_t numArgs = getNumArguments();
580 uint64_t numIns = getInsAttr().getInt();
581 if (numArgs < numIns) {
583 "Cannot have more inputs than arguments, expected at most ")
584 << numArgs <<
", got " << numIns;
591 SmallVectorImpl<OpAsmParser::Argument> &argNames) {
592 if (parser.parseLParen())
598 auto parseArgument = [&]() -> ParseResult {
599 llvm::SMLoc loc = parser.getCurrentLocation();
602 OpAsmParser::Argument argument;
604 auto optArg = parser.parseOptionalArgument(argument);
605 if (optArg.has_value()) {
606 if (succeeded(optArg.value())) {
608 if (argNames.empty() && !argTypes.empty())
609 return parser.emitError(loc,
610 "expected type instead of SSA identifier");
611 argNames.push_back(argument);
613 if (parser.parseColonType(argumentType))
615 }
else if (!argNames.empty()) {
617 return parser.emitError(loc,
"expected SSA identifier");
618 }
else if (parser.parseType(argumentType)) {
624 argTypes.push_back(argumentType);
625 argNames.back().type = argumentType;
631 if (failed(parser.parseOptionalRParen())) {
633 unsigned numTypedArguments = argTypes.size();
637 llvm::SMLoc loc = parser.getCurrentLocation();
638 if (argTypes.size() == numTypedArguments &&
639 succeeded(parser.parseOptionalComma()))
640 return parser.emitError(loc,
"variadic arguments are not allowed");
641 }
while (succeeded(parser.parseOptionalComma()));
642 if (parser.parseRParen())
649 ParseResult llhd::ProcOp::parse(OpAsmParser &parser, OperationState &result) {
651 SmallVector<OpAsmParser::Argument, 8> argNames;
652 SmallVector<Type, 8> argTypes;
653 Builder &
builder = parser.getBuilder();
655 if (parser.parseSymbolName(procName, SymbolTable::getSymbolAttrName(),
662 result.addAttribute(
"ins",
builder.getI64IntegerAttr(argTypes.size()));
663 if (parser.parseArrow())
669 auto type =
builder.getFunctionType(argTypes, std::nullopt);
670 result.addAttribute(circt::llhd::ProcOp::getFunctionTypeAttrName(result.name),
673 auto *body = result.addRegion();
674 if (parser.parseRegion(*body, argNames))
683 ArrayRef<Type> types, uint64_t numIns) {
684 Region &body = op->getRegion(0);
685 auto printList = [&](
unsigned i,
unsigned max) ->
void {
686 for (; i < max; ++i) {
687 p << body.front().getArgument(i) <<
" : " << types[i];
688 p.printOptionalAttrDict(::mlir::function_interface_impl::getArgAttrs(
689 cast<mlir::FunctionOpInterface>(op), i));
697 printList(0, numIns);
699 printList(numIns, types.size());
703 void llhd::ProcOp::print(OpAsmPrinter &printer) {
704 FunctionType type = getFunctionType();
706 printer.printSymbolName(
getName());
710 printer.printRegion(getBody(),
false,
true);
713 Region *llhd::ProcOp::getCallableRegion() {
714 return isExternal() ? nullptr : &getBody();
721 LogicalResult llhd::InstOp::verify() {
723 auto calleeAttr = (*this)->getAttrOfType<FlatSymbolRefAttr>(
"callee");
725 return emitOpError(
"requires a 'callee' symbol reference attribute");
727 auto proc = (*this)->getParentOfType<ModuleOp>().lookupSymbol<llhd::ProcOp>(
728 calleeAttr.getValue());
730 auto type = proc.getFunctionType();
732 if (proc.getIns() != getInputs().size())
733 return emitOpError(
"incorrect number of inputs for proc instantiation");
735 if (type.getNumInputs() != getNumOperands())
736 return emitOpError(
"incorrect number of outputs for proc instantiation");
738 for (
size_t i = 0, e = type.getNumInputs(); i != e; ++i) {
739 if (getOperand(i).getType() != type.getInput(i))
740 return emitOpError(
"operand type mismatch");
747 (*this)->getParentOfType<ModuleOp>().lookupSymbol<llhd::EntityOp>(
748 calleeAttr.getValue());
750 auto type = entity.getFunctionType();
752 if (entity.getIns() != getInputs().size())
753 return emitOpError(
"incorrect number of inputs for entity instantiation");
755 if (type.getNumInputs() != getNumOperands())
757 "incorrect number of outputs for entity instantiation");
759 for (
size_t i = 0, e = type.getNumInputs(); i != e; ++i) {
760 if (getOperand(i).getType() != type.getInput(i))
761 return emitOpError(
"operand type mismatch");
768 (*this)->getParentOfType<ModuleOp>().lookupSymbol<hw::HWModuleOp>(
769 calleeAttr.getValue());
772 if (module.getNumInputPorts() != getInputs().size())
774 "incorrect number of inputs for hw.module instantiation");
776 if (module.getNumOutputPorts() + module.getNumInputPorts() !=
779 "incorrect number of outputs for hw.module instantiation");
782 for (
size_t i = 0, e = module.getNumInputPorts(); i != e; ++i) {
783 if (cast<llhd::SigType>(getOperand(i).getType()).getUnderlyingType() !=
784 module.getInputTypes()[i])
785 return emitOpError(
"input type mismatch");
789 for (
size_t i = 0, e = module.getNumOutputPorts(); i != e; ++i) {
790 if (cast<llhd::SigType>(
791 getOperand(module.getNumInputPorts() + i).getType())
792 .getUnderlyingType() != module.getOutputTypes()[i])
793 return emitOpError(
"output type mismatch");
800 <<
"'" << calleeAttr.getValue()
801 <<
"' does not reference a valid proc, entity, or hw.module";
804 FunctionType llhd::InstOp::getCalleeType() {
805 SmallVector<Type, 8> argTypes(getOperandTypes());
813 LogicalResult llhd::ConnectOp::canonicalize(llhd::ConnectOp op,
814 PatternRewriter &rewriter) {
815 if (op.getLhs() == op.getRhs())
816 rewriter.eraseOp(op);
824 ParseResult llhd::RegOp::parse(OpAsmParser &parser, OperationState &result) {
825 OpAsmParser::UnresolvedOperand signal;
827 SmallVector<OpAsmParser::UnresolvedOperand, 8> valueOperands;
828 SmallVector<OpAsmParser::UnresolvedOperand, 8> triggerOperands;
829 SmallVector<OpAsmParser::UnresolvedOperand, 8> delayOperands;
830 SmallVector<OpAsmParser::UnresolvedOperand, 8> gateOperands;
831 SmallVector<Type, 8> valueTypes;
832 llvm::SmallVector<int64_t, 8> modesArray;
833 llvm::SmallVector<int64_t, 8> gateMask;
834 int64_t gateCount = 0;
836 if (parser.parseOperand(signal))
838 while (succeeded(parser.parseOptionalComma())) {
839 OpAsmParser::UnresolvedOperand value;
840 OpAsmParser::UnresolvedOperand trigger;
841 OpAsmParser::UnresolvedOperand delay;
842 OpAsmParser::UnresolvedOperand gate;
845 NamedAttrList attrStorage;
847 if (parser.parseLParen())
849 if (parser.parseOperand(value) || parser.parseComma())
851 if (parser.parseAttribute(modeAttr, parser.getBuilder().getNoneType(),
852 "modes", attrStorage))
854 auto attrOptional = llhd::symbolizeRegMode(modeAttr.getValue());
856 return parser.emitError(parser.getCurrentLocation(),
857 "invalid string attribute");
858 modesArray.push_back(
static_cast<int64_t
>(*attrOptional));
859 if (parser.parseOperand(trigger))
861 if (parser.parseKeyword(
"after") || parser.parseOperand(delay))
863 if (succeeded(parser.parseOptionalKeyword(
"if"))) {
864 gateMask.push_back(++gateCount);
865 if (parser.parseOperand(gate))
867 gateOperands.push_back(gate);
869 gateMask.push_back(0);
871 if (parser.parseColon() || parser.parseType(valueType) ||
872 parser.parseRParen())
874 valueOperands.push_back(value);
875 triggerOperands.push_back(trigger);
876 delayOperands.push_back(delay);
877 valueTypes.push_back(valueType);
879 if (parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
880 parser.parseType(signalType))
882 if (parser.resolveOperand(signal, signalType, result.operands))
884 if (parser.resolveOperands(valueOperands, valueTypes,
885 parser.getCurrentLocation(), result.operands))
887 for (
auto operand : triggerOperands)
888 if (parser.resolveOperand(operand, parser.getBuilder().getI1Type(),
891 for (
auto operand : delayOperands)
892 if (parser.resolveOperand(
896 for (
auto operand : gateOperands)
897 if (parser.resolveOperand(operand, parser.getBuilder().getI1Type(),
900 result.addAttribute(
"gateMask",
901 parser.getBuilder().getI64ArrayAttr(gateMask));
902 result.addAttribute(
"modes", parser.getBuilder().getI64ArrayAttr(modesArray));
903 llvm::SmallVector<int32_t, 5> operandSizes;
904 operandSizes.push_back(1);
905 operandSizes.push_back(valueOperands.size());
906 operandSizes.push_back(triggerOperands.size());
907 operandSizes.push_back(delayOperands.size());
908 operandSizes.push_back(gateOperands.size());
909 result.addAttribute(
"operandSegmentSizes",
910 parser.getBuilder().getDenseI32ArrayAttr(operandSizes));
915 void llhd::RegOp::print(OpAsmPrinter &printer) {
916 printer <<
" " << getSignal();
917 for (
size_t i = 0, e = getValues().size(); i < e; ++i) {
918 std::optional<llhd::RegMode> mode = llhd::symbolizeRegMode(
919 cast<IntegerAttr>(getModes().getValue()[i]).
getInt());
921 emitError(
"invalid RegMode");
924 printer <<
", (" << getValues()[i] <<
", \""
925 << llhd::stringifyRegMode(*mode) <<
"\" " << getTriggers()[i]
926 <<
" after " << getDelays()[i];
928 printer <<
" if " << getGateAt(i);
929 printer <<
" : " << getValues()[i].getType() <<
")";
931 printer.printOptionalAttrDict((*this)->getAttrs(),
932 {
"modes",
"gateMask",
"operandSegmentSizes"});
933 printer <<
" : " << getSignal().getType();
936 LogicalResult llhd::RegOp::verify() {
938 if (getTriggers().size() < 1)
939 return emitError(
"At least one trigger quadruple has to be present.");
942 if (getValues().size() != getTriggers().size())
943 return emitOpError(
"Number of 'values' is not equal to the number of "
945 << getValues().size() <<
" modes, but " << getTriggers().size()
949 if (getDelays().size() != getTriggers().size())
950 return emitOpError(
"Number of 'delays' is not equal to the number of "
952 << getDelays().size() <<
" modes, but " << getTriggers().size()
957 if (getModes().size() != getTriggers().size())
958 return emitOpError(
"Number of 'modes' is not equal to the number of "
960 << getModes().size() <<
" modes, but " << getTriggers().size()
965 if (getGateMask().size() != getTriggers().size())
966 return emitOpError(
"Size of 'gateMask' is not equal to the size of "
968 << getGateMask().size() <<
" modes, but " << getTriggers().size()
974 unsigned counter = 0;
975 unsigned prevElement = 0;
976 for (Attribute maskElem : getGateMask().getValue()) {
977 int64_t val = cast<IntegerAttr>(maskElem).getInt();
979 return emitError(
"Element in 'gateMask' must not be negative!");
982 if (val != ++prevElement)
984 "'gateMask' has to contain every number from 1 to the "
985 "number of gates minus one exactly once in increasing order "
986 "(may have zeros in-between).");
989 if (getGates().size() != counter)
990 return emitError(
"The number of non-zero elements in 'gateMask' and the "
991 "size of the 'gates' variadic have to match.");
995 for (
auto val : getValues()) {
996 if (val.getType() != getSignal().getType() &&
998 cast<llhd::SigType>(getSignal().getType()).getUnderlyingType()) {
1000 "type of each 'value' has to be either the same as the "
1001 "type of 'signal' or the underlying type of 'signal'");
1007 #include "circt/Dialect/LLHD/IR/LLHDEnums.cpp.inc"
1009 #define GET_OP_CLASSES
1010 #include "circt/Dialect/LLHD/IR/LLHD.cpp.inc"
assert(baseType &&"element must be base type")
static Attribute constFoldTernaryOp(ArrayRef< Attribute > operands, const CalculationT &calculate)
static ParseResult parseArgumentList(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::Argument > &args, SmallVectorImpl< Type > &argTypes)
Parse an argument list of an entity operation.
static void printProcArguments(OpAsmPrinter &p, Operation *op, ArrayRef< Type > types, uint64_t numIns)
Print the signature of the proc unit.
static LogicalResult inferReturnTypesOfStructExtractOp(MLIRContext *context, std::optional< Location > loc, ValueRange operands, DictionaryAttr attrs, mlir::OpaqueProperties properties, mlir::RegionRange regions, SmallVectorImpl< Type > &results)
static void printArgumentList(OpAsmPrinter &printer, std::vector< BlockArgument > args)
static OpFoldResult foldSigPtrArraySliceOp(Op op, ArrayRef< Attribute > operands)
static LogicalResult canonicalizeSigPtrArraySliceOp(Op op, PatternRewriter &rewriter)
static Attribute constFoldUnaryOp(ArrayRef< Attribute > operands, const CalculationT &calculate)
static OpFoldResult foldSigPtrExtractOp(Op op, ArrayRef< Attribute > operands)
static ParseResult parseProcArgumentList(OpAsmParser &parser, SmallVectorImpl< Type > &argTypes, SmallVectorImpl< OpAsmParser::Argument > &argNames)
static ParseResult parseEntitySignature(OpAsmParser &parser, OperationState &result, SmallVectorImpl< OpAsmParser::Argument > &args, SmallVectorImpl< Type > &argTypes)
parse an entity signature with syntax: (arg0 : T0, arg1 : T1, <...>) -> (out0 : T0,...
static std::optional< APInt > getInt(Value value)
Helper to convert a value to a constant integer if it is one.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
LogicalResult inferReturnTypes(MLIRContext *context, std::optional< Location > loc, ValueRange operands, DictionaryAttr attrs, mlir::OpaqueProperties properties, mlir::RegionRange regions, SmallVectorImpl< Type > &results, llvm::function_ref< FIRRTLType(ValueRange, ArrayRef< NamedAttribute >, std::optional< Location >)> callback)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
unsigned getLLHDTypeWidth(Type type)
Type getLLHDElementType(Type type)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.