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 = operands[0].dyn_cast<AttrElementT>()) {
46 }
else if (
auto val = operands[0].dyn_cast<SplatElementsAttr>()) {
49 auto elementResult = calculate(val.getSplatValue<ElementValueT>());
52 if (
auto val = operands[0].dyn_cast<ElementsAttr>()) {
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 (operands[0].isa<AttrElementT>() && operands[1].isa<AttrElementT>() &&
76 operands[2].isa<AttrElementT>()) {
77 auto fst = operands[0].cast<AttrElementT>();
78 auto snd = operands[1].cast<AttrElementT>();
79 auto trd = operands[2].cast<AttrElementT>();
83 calculate(fst.getValue(), snd.getValue(), trd.getValue()));
85 if (operands[0].isa<SplatElementsAttr>() &&
86 operands[1].isa<SplatElementsAttr>() &&
87 operands[2].isa<SplatElementsAttr>()) {
90 auto fst = operands[0].cast<SplatElementsAttr>();
91 auto snd = operands[1].cast<SplatElementsAttr>();
92 auto trd = operands[2].cast<SplatElementsAttr>();
94 auto elementResult = calculate(fst.getSplatValue<ElementValueT>(),
95 snd.getSplatValue<ElementValueT>(),
96 trd.getSplatValue<ElementValueT>());
99 if (operands[0].isa<ElementsAttr>() && operands[1].isa<ElementsAttr>() &&
100 operands[2].isa<ElementsAttr>()) {
103 auto fst = operands[0].cast<ElementsAttr>();
104 auto snd = operands[1].cast<ElementsAttr>();
105 auto trd = operands[2].cast<ElementsAttr>();
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 = type.dyn_cast<llhd::SigType>())
134 type = sig.getUnderlyingType();
135 else if (
auto ptr = type.dyn_cast<llhd::PtrType>())
136 type = ptr.getUnderlyingType();
137 if (
auto array = type.dyn_cast<hw::ArrayType>())
138 return array.getNumElements();
139 if (
auto tup = type.dyn_cast<hw::StructType>())
140 return tup.getElements().size();
141 return type.getIntOrFloatBitWidth();
145 if (
auto sig = type.dyn_cast<llhd::SigType>())
146 type = sig.getUnderlyingType();
147 else if (
auto ptr = type.dyn_cast<llhd::PtrType>())
148 type = ptr.getUnderlyingType();
149 if (
auto array = type.dyn_cast<hw::ArrayType>())
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 operands[1].cast<IntegerAttr>().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 operands[1].cast<IntegerAttr>().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) {
270 Type type = operands[0]
274 .template cast<hw::StructType>()
275 .getFieldType(attrs.getNamed(
"field")
280 context->getDiagEngine().emit(loc.value_or(UnknownLoc()),
281 DiagnosticSeverity::Error)
282 <<
"invalid field name specified";
290 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
291 DictionaryAttr attrs, mlir::OpaqueProperties properties,
292 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
293 return inferReturnTypesOfStructExtractOp<llhd::SigType>(
294 context, loc, operands, attrs, properties, regions, results);
298 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
299 DictionaryAttr attrs, mlir::OpaqueProperties properties,
300 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
301 return inferReturnTypesOfStructExtractOp<llhd::PtrType>(
302 context, loc, operands, attrs, properties, regions, results);
309 LogicalResult llhd::DrvOp::fold(FoldAdaptor adaptor,
310 SmallVectorImpl<OpFoldResult> &result) {
314 if (matchPattern(getEnable(), m_One())) {
315 getEnableMutable().clear();
322 LogicalResult llhd::DrvOp::canonicalize(llhd::DrvOp op,
323 PatternRewriter &rewriter) {
327 if (matchPattern(op.getEnable(), m_Zero())) {
328 rewriter.eraseOp(op);
340 SuccessorOperands llhd::WaitOp::getSuccessorOperands(
unsigned index) {
341 assert(index == 0 &&
"invalid successor index");
342 return SuccessorOperands(getDestOpsMutable());
354 SmallVectorImpl<OpAsmParser::Argument> &args,
355 SmallVectorImpl<Type> &argTypes) {
356 auto parseElt = [&]() -> ParseResult {
357 OpAsmParser::Argument argument;
359 auto optArg = parser.parseOptionalArgument(argument);
360 if (optArg.has_value()) {
361 if (succeeded(optArg.value())) {
362 if (!argument.ssaName.name.empty() &&
363 succeeded(parser.parseColonType(argType))) {
364 args.push_back(argument);
365 argTypes.push_back(argType);
366 args.back().type = argType;
373 return parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
381 SmallVectorImpl<OpAsmParser::Argument> &args,
382 SmallVectorImpl<Type> &argTypes) {
386 IntegerAttr insAttr = parser.getBuilder().getI64IntegerAttr(args.size());
387 result.addAttribute(
"ins", insAttr);
388 if (succeeded(parser.parseOptionalArrow()))
395 ParseResult llhd::EntityOp::parse(OpAsmParser &parser, OperationState &result) {
396 StringAttr entityName;
397 SmallVector<OpAsmParser::Argument, 4> args;
398 SmallVector<Type, 4> argTypes;
400 if (parser.parseSymbolName(entityName, SymbolTable::getSymbolAttrName(),
407 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
410 auto type = parser.getBuilder().getFunctionType(argTypes, std::nullopt);
412 circt::llhd::EntityOp::getFunctionTypeAttrName(result.name),
415 auto &body = *result.addRegion();
416 if (parser.parseRegion(body, args))
419 body.push_back(std::make_unique<Block>().release());
425 std::vector<BlockArgument> args) {
427 llvm::interleaveComma(args, printer, [&](BlockArgument arg) {
428 printer << arg <<
" : " << arg.getType();
433 void llhd::EntityOp::print(OpAsmPrinter &printer) {
434 std::vector<BlockArgument> ins,
outs;
435 uint64_t nIns = getInsAttr().getInt();
436 for (uint64_t i = 0; i < getBody().front().getArguments().size(); ++i) {
440 ins.push_back(getBody().front().getArguments()[i]);
442 outs.push_back(getBody().front().getArguments()[i]);
447 ->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName())
450 printer.printSymbolName(entityName);
455 printer.printOptionalAttrDictWithKeyword(
457 {SymbolTable::getSymbolAttrName(),
458 getFunctionTypeAttrName(),
"ins"});
460 printer.printRegion(getBody(),
false,
false);
463 LogicalResult llhd::EntityOp::verify() {
464 uint64_t numArgs = getNumArguments();
465 uint64_t nIns = getInsAttr().getInt();
467 if (numArgs < nIns) {
469 "Cannot have more inputs than arguments, expected at most ")
470 << numArgs <<
" but got: " << nIns;
474 for (
size_t i = 0; i < numArgs; ++i)
475 if (!getArgument(i).getType().isa<llhd::SigType>())
476 return emitError(
"usage of invalid argument type. Got ")
477 << getArgument(i).getType() <<
", expected LLHD signal type";
482 LogicalResult circt::llhd::EntityOp::verifyType() {
483 FunctionType type = getFunctionType();
487 if (type.getNumResults() > 0)
488 return emitOpError(
"an entity cannot have return types.");
491 for (Type inputType : type.getInputs())
492 if (!inputType.isa<llhd::SigType>())
493 return emitOpError(
"usage of invalid argument type. Got ")
494 << inputType <<
", expected LLHD signal type";
499 LogicalResult circt::llhd::EntityOp::verifyBody() {
501 llvm::StringSet<> sigSet;
502 llvm::StringSet<> instSet;
503 auto walkResult = walk([&sigSet, &instSet](Operation *op) -> WalkResult {
504 return TypeSwitch<Operation *, WalkResult>(op)
505 .Case<SigOp>([&](
auto sigOp) -> WalkResult {
506 if (!sigSet.insert(sigOp.getName()).second)
507 return sigOp.emitError(
"redefinition of signal named '")
508 << sigOp.getName() <<
"'!";
512 .Case<OutputOp>([&](
auto outputOp) -> WalkResult {
513 if (outputOp.getName() && !sigSet.insert(*outputOp.getName()).second)
514 return outputOp.emitError(
"redefinition of signal named '")
515 << *outputOp.getName() <<
"'!";
519 .Case<InstOp>([&](
auto instOp) -> WalkResult {
520 if (!instSet.insert(instOp.getName()).second)
521 return instOp.emitError(
"redefinition of instance named '")
522 << instOp.getName() <<
"'!";
526 .Default([](
auto op) -> WalkResult {
return WalkResult::advance(); });
529 return failure(walkResult.wasInterrupted());
533 ArrayRef<Type> llhd::EntityOp::getArgumentTypes() {
534 return getFunctionType().getInputs();
538 ArrayRef<Type> llhd::EntityOp::getResultTypes() {
539 return getFunctionType().getResults();
542 Region *llhd::EntityOp::getCallableRegion() {
543 return isExternal() ? nullptr : &getBody();
550 LogicalResult circt::llhd::ProcOp::verifyType() {
553 if (getNumResults() > 0) {
555 "process has more than zero return types, this is not allowed");
559 for (
int i = 0, e = getNumArguments(); i < e; ++i) {
560 if (!getArgument(i).getType().isa<llhd::SigType>()) {
561 return emitOpError(
"usage of invalid argument type, was ")
562 << getArgument(i).getType() <<
", expected LLHD signal type";
569 ArrayRef<Type> llhd::ProcOp::getArgumentTypes() {
570 return getFunctionType().getInputs();
574 ArrayRef<Type> llhd::ProcOp::getResultTypes() {
575 return getFunctionType().getResults();
578 LogicalResult circt::llhd::ProcOp::verifyBody() {
return success(); }
580 LogicalResult llhd::ProcOp::verify() {
583 uint64_t numArgs = getNumArguments();
584 uint64_t numIns = getInsAttr().getInt();
585 if (numArgs < numIns) {
587 "Cannot have more inputs than arguments, expected at most ")
588 << numArgs <<
", got " << numIns;
595 SmallVectorImpl<OpAsmParser::Argument> &argNames) {
596 if (parser.parseLParen())
602 auto parseArgument = [&]() -> ParseResult {
603 llvm::SMLoc loc = parser.getCurrentLocation();
606 OpAsmParser::Argument argument;
608 auto optArg = parser.parseOptionalArgument(argument);
609 if (optArg.has_value()) {
610 if (succeeded(optArg.value())) {
612 if (argNames.empty() && !argTypes.empty())
613 return parser.emitError(loc,
614 "expected type instead of SSA identifier");
615 argNames.push_back(argument);
617 if (parser.parseColonType(argumentType))
619 }
else if (!argNames.empty()) {
621 return parser.emitError(loc,
"expected SSA identifier");
622 }
else if (parser.parseType(argumentType)) {
628 argTypes.push_back(argumentType);
629 argNames.back().type = argumentType;
635 if (failed(parser.parseOptionalRParen())) {
637 unsigned numTypedArguments = argTypes.size();
641 llvm::SMLoc loc = parser.getCurrentLocation();
642 if (argTypes.size() == numTypedArguments &&
643 succeeded(parser.parseOptionalComma()))
644 return parser.emitError(loc,
"variadic arguments are not allowed");
645 }
while (succeeded(parser.parseOptionalComma()));
646 if (parser.parseRParen())
653 ParseResult llhd::ProcOp::parse(OpAsmParser &parser, OperationState &result) {
655 SmallVector<OpAsmParser::Argument, 8> argNames;
656 SmallVector<Type, 8> argTypes;
657 Builder &
builder = parser.getBuilder();
659 if (parser.parseSymbolName(procName, SymbolTable::getSymbolAttrName(),
666 result.addAttribute(
"ins",
builder.getI64IntegerAttr(argTypes.size()));
667 if (parser.parseArrow())
673 auto type =
builder.getFunctionType(argTypes, std::nullopt);
674 result.addAttribute(circt::llhd::ProcOp::getFunctionTypeAttrName(result.name),
677 auto *body = result.addRegion();
678 if (parser.parseRegion(*body, argNames))
687 ArrayRef<Type> types, uint64_t numIns) {
688 Region &body = op->getRegion(0);
689 auto printList = [&](
unsigned i,
unsigned max) ->
void {
690 for (; i < max; ++i) {
691 p << body.front().getArgument(i) <<
" : " << types[i];
692 p.printOptionalAttrDict(::mlir::function_interface_impl::getArgAttrs(
693 cast<mlir::FunctionOpInterface>(op), i));
701 printList(0, numIns);
703 printList(numIns, types.size());
707 void llhd::ProcOp::print(OpAsmPrinter &printer) {
708 FunctionType type = getFunctionType();
710 printer.printSymbolName(
getName());
714 printer.printRegion(getBody(),
false,
true);
717 Region *llhd::ProcOp::getCallableRegion() {
718 return isExternal() ? nullptr : &getBody();
725 LogicalResult llhd::InstOp::verify() {
727 auto calleeAttr = (*this)->getAttrOfType<FlatSymbolRefAttr>(
"callee");
729 return emitOpError(
"requires a 'callee' symbol reference attribute");
731 auto proc = (*this)->getParentOfType<ModuleOp>().lookupSymbol<llhd::ProcOp>(
732 calleeAttr.getValue());
734 auto type = proc.getFunctionType();
736 if (proc.getIns() != getInputs().size())
737 return emitOpError(
"incorrect number of inputs for proc instantiation");
739 if (type.getNumInputs() != getNumOperands())
740 return emitOpError(
"incorrect number of outputs for proc instantiation");
742 for (
size_t i = 0, e = type.getNumInputs(); i != e; ++i) {
743 if (getOperand(i).getType() != type.getInput(i))
744 return emitOpError(
"operand type mismatch");
751 (*this)->getParentOfType<ModuleOp>().lookupSymbol<llhd::EntityOp>(
752 calleeAttr.getValue());
754 auto type = entity.getFunctionType();
756 if (entity.getIns() != getInputs().size())
757 return emitOpError(
"incorrect number of inputs for entity instantiation");
759 if (type.getNumInputs() != getNumOperands())
761 "incorrect number of outputs for entity instantiation");
763 for (
size_t i = 0, e = type.getNumInputs(); i != e; ++i) {
764 if (getOperand(i).getType() != type.getInput(i))
765 return emitOpError(
"operand type mismatch");
772 (*this)->getParentOfType<ModuleOp>().lookupSymbol<hw::HWModuleOp>(
773 calleeAttr.getValue());
776 if (module.getNumInputPorts() != getInputs().size())
778 "incorrect number of inputs for hw.module instantiation");
780 if (module.getNumOutputPorts() + module.getNumInputPorts() !=
783 "incorrect number of outputs for hw.module instantiation");
786 for (
size_t i = 0, e = module.getNumInputPorts(); i != e; ++i) {
787 if (getOperand(i).getType().cast<llhd::SigType>().getUnderlyingType() !=
788 module.getInputTypes()[i])
789 return emitOpError(
"input type mismatch");
793 for (
size_t i = 0, e = module.getNumOutputPorts(); i != e; ++i) {
794 if (getOperand(module.getNumInputPorts() + i)
796 .cast<llhd::SigType>()
797 .getUnderlyingType() != module.getOutputTypes()[i])
798 return emitOpError(
"output type mismatch");
805 <<
"'" << calleeAttr.getValue()
806 <<
"' does not reference a valid proc, entity, or hw.module";
809 FunctionType llhd::InstOp::getCalleeType() {
810 SmallVector<Type, 8> argTypes(getOperandTypes());
818 LogicalResult llhd::ConnectOp::canonicalize(llhd::ConnectOp op,
819 PatternRewriter &rewriter) {
820 if (op.getLhs() == op.getRhs())
821 rewriter.eraseOp(op);
829 ParseResult llhd::RegOp::parse(OpAsmParser &parser, OperationState &result) {
830 OpAsmParser::UnresolvedOperand signal;
832 SmallVector<OpAsmParser::UnresolvedOperand, 8> valueOperands;
833 SmallVector<OpAsmParser::UnresolvedOperand, 8> triggerOperands;
834 SmallVector<OpAsmParser::UnresolvedOperand, 8> delayOperands;
835 SmallVector<OpAsmParser::UnresolvedOperand, 8> gateOperands;
836 SmallVector<Type, 8> valueTypes;
837 llvm::SmallVector<int64_t, 8> modesArray;
838 llvm::SmallVector<int64_t, 8> gateMask;
839 int64_t gateCount = 0;
841 if (parser.parseOperand(signal))
843 while (succeeded(parser.parseOptionalComma())) {
844 OpAsmParser::UnresolvedOperand
value;
845 OpAsmParser::UnresolvedOperand trigger;
846 OpAsmParser::UnresolvedOperand delay;
847 OpAsmParser::UnresolvedOperand gate;
850 NamedAttrList attrStorage;
852 if (parser.parseLParen())
854 if (parser.parseOperand(
value) || parser.parseComma())
856 if (parser.parseAttribute(modeAttr, parser.getBuilder().getNoneType(),
857 "modes", attrStorage))
859 auto attrOptional = llhd::symbolizeRegMode(modeAttr.getValue());
861 return parser.emitError(parser.getCurrentLocation(),
862 "invalid string attribute");
863 modesArray.push_back(
static_cast<int64_t
>(*attrOptional));
864 if (parser.parseOperand(trigger))
866 if (parser.parseKeyword(
"after") || parser.parseOperand(delay))
868 if (succeeded(parser.parseOptionalKeyword(
"if"))) {
869 gateMask.push_back(++gateCount);
870 if (parser.parseOperand(gate))
872 gateOperands.push_back(gate);
874 gateMask.push_back(0);
876 if (parser.parseColon() || parser.parseType(valueType) ||
877 parser.parseRParen())
879 valueOperands.push_back(
value);
880 triggerOperands.push_back(trigger);
881 delayOperands.push_back(delay);
882 valueTypes.push_back(valueType);
884 if (parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
885 parser.parseType(signalType))
887 if (parser.resolveOperand(signal, signalType, result.operands))
889 if (parser.resolveOperands(valueOperands, valueTypes,
890 parser.getCurrentLocation(), result.operands))
892 for (
auto operand : triggerOperands)
893 if (parser.resolveOperand(operand, parser.getBuilder().getI1Type(),
896 for (
auto operand : delayOperands)
897 if (parser.resolveOperand(
901 for (
auto operand : gateOperands)
902 if (parser.resolveOperand(operand, parser.getBuilder().getI1Type(),
905 result.addAttribute(
"gateMask",
906 parser.getBuilder().getI64ArrayAttr(gateMask));
907 result.addAttribute(
"modes", parser.getBuilder().getI64ArrayAttr(modesArray));
908 llvm::SmallVector<int32_t, 5> operandSizes;
909 operandSizes.push_back(1);
910 operandSizes.push_back(valueOperands.size());
911 operandSizes.push_back(triggerOperands.size());
912 operandSizes.push_back(delayOperands.size());
913 operandSizes.push_back(gateOperands.size());
914 result.addAttribute(
"operandSegmentSizes",
915 parser.getBuilder().getDenseI32ArrayAttr(operandSizes));
920 void llhd::RegOp::print(OpAsmPrinter &printer) {
921 printer <<
" " << getSignal();
922 for (
size_t i = 0, e = getValues().size(); i < e; ++i) {
923 std::optional<llhd::RegMode> mode = llhd::symbolizeRegMode(
924 getModes().getValue()[i].cast<IntegerAttr>().
getInt());
926 emitError(
"invalid RegMode");
929 printer <<
", (" << getValues()[i] <<
", \""
930 << llhd::stringifyRegMode(*mode) <<
"\" " << getTriggers()[i]
931 <<
" after " << getDelays()[i];
933 printer <<
" if " << getGateAt(i);
934 printer <<
" : " << getValues()[i].getType() <<
")";
936 printer.printOptionalAttrDict((*this)->getAttrs(),
937 {
"modes",
"gateMask",
"operandSegmentSizes"});
938 printer <<
" : " << getSignal().getType();
941 LogicalResult llhd::RegOp::verify() {
943 if (getTriggers().size() < 1)
944 return emitError(
"At least one trigger quadruple has to be present.");
947 if (getValues().size() != getTriggers().size())
948 return emitOpError(
"Number of 'values' is not equal to the number of "
950 << getValues().size() <<
" modes, but " << getTriggers().size()
954 if (getDelays().size() != getTriggers().size())
955 return emitOpError(
"Number of 'delays' is not equal to the number of "
957 << getDelays().size() <<
" modes, but " << getTriggers().size()
962 if (getModes().size() != getTriggers().size())
963 return emitOpError(
"Number of 'modes' is not equal to the number of "
965 << getModes().size() <<
" modes, but " << getTriggers().size()
970 if (getGateMask().size() != getTriggers().size())
971 return emitOpError(
"Size of 'gateMask' is not equal to the size of "
973 << getGateMask().size() <<
" modes, but " << getTriggers().size()
979 unsigned counter = 0;
980 unsigned prevElement = 0;
981 for (Attribute maskElem : getGateMask().getValue()) {
982 int64_t val = maskElem.cast<IntegerAttr>().
getInt();
984 return emitError(
"Element in 'gateMask' must not be negative!");
987 if (val != ++prevElement)
989 "'gateMask' has to contain every number from 1 to the "
990 "number of gates minus one exactly once in increasing order "
991 "(may have zeros in-between).");
994 if (getGates().size() != counter)
995 return emitError(
"The number of non-zero elements in 'gateMask' and the "
996 "size of the 'gates' variadic have to match.");
1000 for (
auto val : getValues()) {
1001 if (val.getType() != getSignal().getType() &&
1003 getSignal().getType().cast<llhd::SigType>().getUnderlyingType()) {
1005 "type of each 'value' has to be either the same as the "
1006 "type of 'signal' or the underlying type of 'signal'");
1012 #include "circt/Dialect/LLHD/IR/LLHDEnums.cpp.inc"
1014 #define GET_OP_CLASSES
1015 #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)
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
mlir::raw_indented_ostream & outs()