14#include "mlir/IR/Attributes.h"
15#include "mlir/IR/BuiltinDialect.h"
16#include "mlir/IR/BuiltinTypes.h"
17#include "mlir/IR/Matchers.h"
18#include "mlir/IR/PatternMatch.h"
19#include "mlir/IR/Region.h"
20#include "mlir/IR/Types.h"
21#include "mlir/IR/Value.h"
22#include "mlir/Interfaces/FunctionImplementation.h"
23#include "llvm/ADT/ArrayRef.h"
24#include "llvm/ADT/SmallVector.h"
31 if (
auto sig = dyn_cast<RefType>(type))
32 type = sig.getNestedType();
33 if (
auto array = dyn_cast<hw::ArrayType>(type))
34 return array.getNumElements();
36 return tup.getElements().size();
37 return type.getIntOrFloatBitWidth();
41 if (
auto sig = dyn_cast<RefType>(type))
42 type = sig.getNestedType();
43 if (
auto array = dyn_cast<hw::ArrayType>(type))
44 return array.getElementType();
48template <
typename... OpTypes>
50 for (
auto *user : op->getUsers()) {
51 if (isa<OpTypes...>(user))
61OpFoldResult llhd::ConstantTimeOp::fold(FoldAdaptor adaptor) {
62 assert(adaptor.getOperands().empty() &&
"const has no operands");
63 return getValueAttr();
66void llhd::ConstantTimeOp::build(OpBuilder &builder, OperationState &result,
67 uint64_t time,
const StringRef &timeUnit,
69 auto *ctx = builder.getContext();
70 auto attr = TimeAttr::get(ctx, time, timeUnit, delta);
71 return build(builder, result, TimeType::get(ctx), attr);
79 unsigned index, Type resultType) {
80 return TypeSwitch<Type, Value>(val.getType())
81 .Case<hw::StructType>([&](hw::StructType ty) -> Value {
83 ty.getElements()[index].name);
85 .Case<hw::ArrayType>([&](hw::ArrayType ty) -> Value {
88 builder.getIntegerType(llvm::Log2_64_Ceil(ty.getNumElements())),
92 .Case<IntegerType>([&](IntegerType ty) -> Value {
94 resultType.getIntOrFloatBitWidth());
100 setNameFn(getResult(), *
getName());
108static std::optional<DenseMap<Attribute, Type>>
110 int width = type.getIntOrFloatBitWidth();
116 SmallVector<bool> startIndices(width,
false);
117 for (Operation *user : value.getUsers()) {
118 if (
auto extract = dyn_cast<SigExtractOp>(user)) {
120 if (matchPattern(extract.getLowBit(), m_ConstantInt(&lowBit))) {
121 startIndices[lowBit.getZExtValue()] =
true;
122 int64_t highBit = lowBit.getZExtValue() + extract.getResultWidth();
124 startIndices[highBit] =
true;
128 if (isa<ProbeOp, DriveLikeOp>(user)) {
138 DenseMap<Attribute, Type> destructured;
139 for (
int start = 0; start < width;) {
141 while (end < width && !startIndices[end])
144 int runLength = end - start;
147 {IntegerAttr::get(IndexType::get(type.getContext()), start),
148 IntegerType::get(type.getContext(), runLength)});
155static std::optional<DenseMap<Attribute, Type>>
160 if (
auto intType = dyn_cast<IntegerType>(type)) {
163 auto destructurable = llvm::dyn_cast<DestructurableTypeInterface>(type);
166 return destructurable.getSubelementIndexMap();
170SmallVector<DestructurableMemorySlot> SignalOp::getDestructurableSlots() {
171 auto type = getType().getNestedType();
175 if (!
hasUserOfKind<SigExtractOp, SigArrayGetOp, SigStructExtractOp,
176 SigArraySliceOp>(*
this))
180 if (!destructuredType)
182 return {DestructurableMemorySlot{{getResult(), type}, *destructuredType}};
185DenseMap<Attribute, MemorySlot> SignalOp::destructure(
186 const DestructurableMemorySlot &slot,
187 const SmallPtrSetImpl<Attribute> &usedIndices, OpBuilder &builder,
188 SmallVectorImpl<DestructurableAllocationOpInterface> &newAllocators) {
189 assert(slot.ptr == getResult());
190 builder.setInsertionPointAfter(*
this);
192 DenseMap<Attribute, Type> subelementTypes = slot.subelementTypes;
193 DenseMap<Attribute, MemorySlot> slotMap;
194 SmallVector<std::pair<unsigned, Type>> indices;
195 for (
auto attr : usedIndices) {
196 assert(isa<IntegerAttr>(attr));
197 auto elemType = subelementTypes.at(attr);
198 assert(elemType &&
"used index must exist");
199 indices.push_back({cast<IntegerAttr>(attr).getInt(), elemType});
202 llvm::sort(indices, [](
auto a,
auto b) {
return a.first < b.first; });
204 for (
auto [index, type] : indices) {
208 auto sigOp = SignalOp::create(builder,
getLoc(), RefType::get(type),
209 getNameAttr(), init);
210 newAllocators.push_back(sigOp);
211 slotMap.try_emplace<MemorySlot>(
212 IntegerAttr::get(IndexType::get(getContext()), index),
213 {sigOp.getResult(), type});
219std::optional<DestructurableAllocationOpInterface>
220SignalOp::handleDestructuringComplete(
const DestructurableMemorySlot &slot,
221 OpBuilder &builder) {
222 assert(slot.ptr == getResult());
233 setNameFn(getResult(), *
getName());
247 if (op.getResultWidth() == op.getInputWidth() &&
248 cast<IntegerAttr>(operands[1]).getValue().isZero())
249 return op.getInput();
254OpFoldResult llhd::SigExtractOp::fold(FoldAdaptor adaptor) {
260 return std::max<int64_t>(0, std::min(a2, b2) - std::max(a1, b1));
264 SmallVectorImpl<std::pair<unsigned, Value>> &sorted) {
265 for (
auto [attr, mem] : subslots) {
266 assert(isa<IntegerAttr>(attr));
267 sorted.push_back({cast<IntegerAttr>(attr).getInt(), mem.ptr});
270 llvm::sort(sorted, [](
auto a,
auto b) {
return a.first < b.first; });
274 SmallVectorImpl<std::pair<unsigned, Type>> &sorted) {
275 for (
auto [attr, mem] : subslots) {
276 assert(isa<IntegerAttr>(attr));
277 sorted.push_back({cast<IntegerAttr>(attr).getInt(), mem});
280 llvm::sort(sorted, [](
auto a,
auto b) {
return a.first < b.first; });
283bool SigExtractOp::canRewire(
const DestructurableMemorySlot &slot,
284 SmallPtrSetImpl<Attribute> &usedIndices,
285 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
286 const DataLayout &dataLayout) {
287 if (slot.ptr != getInput())
291 if (!type.isSignlessInteger())
293 if (!matchPattern(getLowBit(), m_ConstantInt(&idx)))
299 for (Operation *user : getResult().getUsers()) {
300 if (!isa<ProbeOp, DriveLikeOp>(user))
304 SmallVector<std::pair<unsigned, Type>> elements;
307 int64_t index = idx.getZExtValue();
309 int64_t coveredBits = 0;
310 for (
auto [start, type] : elements) {
311 int64_t subslotWidth = type.getIntOrFloatBitWidth();
316 usedIndices.insert(IntegerAttr::get(IndexType::get(getContext()), start));
317 coveredBits += overlap;
320 if (coveredBits != width)
323 mustBeSafelyUsed.emplace_back<MemorySlot>({getResult(), type});
327DeletionKind SigExtractOp::rewire(
const DestructurableMemorySlot &slot,
328 DenseMap<Attribute, MemorySlot> &subslots,
330 const DataLayout &dataLayout) {
332 [[maybe_unused]]
bool result = matchPattern(getLowBit(), m_ConstantInt(&idx));
335 int64_t idxVal = idx.getZExtValue();
337 SmallVector<std::pair<unsigned, Value>> elements;
340 for (Operation *user : llvm::make_early_inc_range(getResult().getUsers())) {
341 builder.setInsertionPoint(user);
343 if (
auto probeOp = dyn_cast<ProbeOp>(user)) {
344 SmallVector<Value> values;
345 for (
auto [start, value] : elements) {
346 int64_t subslotWidth = cast<RefType>(value.getType())
348 .getIntOrFloatBitWidth();
350 start + subslotWidth);
353 values.push_back(ProbeOp::create(builder, probeOp.getLoc(), value));
355 std::reverse(values.begin(), values.end());
356 Value value = comb::ConcatOp::create(builder, probeOp.getLoc(), values);
357 probeOp.replaceAllUsesWith(value);
363 auto driveLike = cast<DriveLikeOp>(user);
364 Value driven = driveLike.getValue();
365 Value time = driveLike.getTime();
366 Value enable = driveLike.getEnable();
367 for (
auto [start, sig] : elements) {
368 int64_t subslotWidth =
369 cast<RefType>(sig.getType()).getNestedType().getIntOrFloatBitWidth();
375 start - idxVal, subslotWidth);
377 DriveOp::create(builder, user->getLoc(), sig, val, time, enable);
379 AssignOp::create(builder, user->getLoc(), sig, val, enable);
384 return DeletionKind::Delete;
387LogicalResult SigExtractOp::ensureOnlySafeAccesses(
388 const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
389 const DataLayout &dataLayout) {
397OpFoldResult llhd::SigArraySliceOp::fold(FoldAdaptor adaptor) {
398 auto lowIndex = dyn_cast_or_null<IntegerAttr>(adaptor.getLowIndex());
403 if (getResultWidth() == getInputWidth() && lowIndex.getValue().isZero())
411 PatternRewriter &rewriter) {
412 IntegerAttr indexAttr;
413 if (!matchPattern(op.getLowIndex(), m_Constant(&indexAttr)))
419 if (matchPattern(op.getInput(),
420 m_Op<Op>(matchers::m_Any(), m_Constant(&a)))) {
421 auto sliceOp = op.getInput().template getDefiningOp<Op>();
422 rewriter.modifyOpInPlace(op, [&]() {
423 op.getInputMutable().assign(sliceOp.getInput());
425 rewriter, op->getLoc(), a.getValue() + indexAttr.getValue());
426 op.getLowIndexMutable().assign(newIndex);
435LogicalResult llhd::SigArraySliceOp::canonicalize(llhd::SigArraySliceOp op,
436 PatternRewriter &rewriter) {
444bool SigArrayGetOp::canRewire(
const DestructurableMemorySlot &slot,
445 SmallPtrSetImpl<Attribute> &usedIndices,
446 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
447 const DataLayout &dataLayout) {
448 if (slot.ptr != getInput())
451 if (!matchPattern(getIndex(), m_ConstantInt(&idx)))
454 IntegerAttr::get(IndexType::get(getContext()), idx.getZExtValue());
455 if (!slot.subelementTypes.contains(index))
457 usedIndices.insert(index);
458 mustBeSafelyUsed.emplace_back<MemorySlot>(
459 {getResult(), cast<RefType>(getResult().getType()).getNestedType()});
463DeletionKind SigArrayGetOp::rewire(
const DestructurableMemorySlot &slot,
464 DenseMap<Attribute, MemorySlot> &subslots,
466 const DataLayout &dataLayout) {
468 bool result = matchPattern(getIndex(), m_ConstantInt(&idx));
472 IntegerAttr::get(IndexType::get(getContext()), idx.getZExtValue());
473 auto it = subslots.find(index);
474 assert(it != subslots.end());
475 replaceAllUsesWith(it->getSecond().ptr);
476 return DeletionKind::Delete;
479LogicalResult SigArrayGetOp::ensureOnlySafeAccesses(
480 const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
481 const DataLayout &dataLayout) {
489LogicalResult llhd::SigStructExtractOp::inferReturnTypes(
490 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
491 DictionaryAttr
attrs, mlir::PropertyRef properties,
492 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
493 typename SigStructExtractOp::Adaptor adaptor(operands,
attrs, properties,
495 auto nestedType = cast<RefType>(adaptor.getInput().getType()).getNestedType();
500 fieldType = structType.getFieldType(adaptor.getField());
501 }
else if (
auto unionType = dyn_cast<hw::UnionType>(nestedType)) {
502 fieldType = unionType.getFieldType(adaptor.getField());
504 context->getDiagEngine().emit(loc.value_or(UnknownLoc()),
505 DiagnosticSeverity::Error)
506 <<
"expected struct or union type";
511 context->getDiagEngine().emit(loc.value_or(UnknownLoc()),
512 DiagnosticSeverity::Error)
513 <<
"invalid field name specified";
516 results.push_back(RefType::get(fieldType));
520bool SigStructExtractOp::canRewire(
521 const DestructurableMemorySlot &slot,
522 SmallPtrSetImpl<Attribute> &usedIndices,
523 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
524 const DataLayout &dataLayout) {
525 if (slot.ptr != getInput())
528 auto nestedType = cast<RefType>(getInput().getType()).getNestedType();
529 std::optional<uint32_t> index;
533 index = structType.getFieldIndex(getFieldAttr());
534 else if (
auto unionType = dyn_cast<hw::UnionType>(nestedType))
535 index = unionType.getFieldIndex(getFieldAttr());
541 auto indexAttr = IntegerAttr::get(IndexType::get(getContext()), *index);
542 if (!slot.subelementTypes.contains(indexAttr))
544 usedIndices.insert(indexAttr);
545 mustBeSafelyUsed.emplace_back<MemorySlot>(
546 {getResult(), cast<RefType>(getResult().getType()).getNestedType()});
551SigStructExtractOp::rewire(
const DestructurableMemorySlot &slot,
552 DenseMap<Attribute, MemorySlot> &subslots,
553 OpBuilder &builder,
const DataLayout &dataLayout) {
554 auto nestedType = cast<RefType>(getInput().getType()).getNestedType();
555 std::optional<unsigned> index;
557 index = structTy.getFieldIndex(getFieldAttr());
558 else if (
auto unionTy = dyn_cast<hw::UnionType>(nestedType))
559 index = unionTy.getFieldIndex(getFieldAttr());
560 assert(index.has_value());
561 auto indexAttr = IntegerAttr::get(IndexType::get(getContext()), *index);
562 auto it = subslots.find(indexAttr);
563 assert(it != subslots.end());
564 replaceAllUsesWith(it->getSecond().ptr);
565 return DeletionKind::Delete;
568LogicalResult SigStructExtractOp::ensureOnlySafeAccesses(
569 const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
570 const DataLayout &dataLayout) {
578bool ProbeOp::canRewire(
const DestructurableMemorySlot &slot,
579 SmallPtrSetImpl<Attribute> &usedIndices,
580 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
581 const DataLayout &dataLayout) {
582 for (
auto [key, _] : slot.subelementTypes)
583 usedIndices.insert(key);
585 return isa<hw::StructType, hw::ArrayType, IntegerType>(slot.valueType);
588DeletionKind ProbeOp::rewire(
const DestructurableMemorySlot &slot,
589 DenseMap<Attribute, MemorySlot> &subslots,
590 OpBuilder &builder,
const DataLayout &dataLayout) {
591 SmallVector<std::pair<unsigned, Value>> elements;
592 SmallVector<Value> probed;
594 for (
auto [_, val] : elements)
595 probed.push_back(ProbeOp::create(builder,
getLoc(), val));
598 TypeSwitch<Type, Value>(getType())
599 .Case<hw::StructType>([&](
auto ty) {
603 .Case<hw::ArrayType>([&](
auto ty) {
604 std::reverse(probed.begin(), probed.end());
607 .Case<IntegerType>([&](
auto ty) {
608 std::reverse(probed.begin(), probed.end());
609 return comb::ConcatOp::create(builder,
getLoc(), probed);
612 replaceAllUsesWith(repl);
613 return DeletionKind::Delete;
617ProbeOp::ensureOnlySafeAccesses(
const MemorySlot &slot,
618 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
619 const DataLayout &dataLayout) {
623void ProbeOp::getEffects(
624 SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
626 if (mayHaveSSADominance(*getOperation()->getParentRegion()))
627 effects.emplace_back(MemoryEffects::Read::get(), &getSignalMutable());
634LogicalResult ProbeNetOp::ensureOnlySafeAccesses(
635 const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
636 const DataLayout &dataLayout) {
640void ProbeNetOp::getEffects(
641 SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
643 if (mayHaveSSADominance(*getOperation()->getParentRegion()))
644 effects.emplace_back(MemoryEffects::Read::get(), &getSignalMutable());
651LogicalResult llhd::DriveOp::fold(FoldAdaptor adaptor,
652 SmallVectorImpl<OpFoldResult> &result) {
656 if (matchPattern(getEnable(), m_One())) {
657 getEnableMutable().clear();
664LogicalResult llhd::DriveOp::canonicalize(llhd::DriveOp op,
665 PatternRewriter &rewriter) {
669 if (matchPattern(op.getEnable(), m_Zero())) {
670 rewriter.eraseOp(op);
677bool DriveOp::canRewire(
const DestructurableMemorySlot &slot,
678 SmallPtrSetImpl<Attribute> &usedIndices,
679 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
680 const DataLayout &dataLayout) {
681 for (
auto [key, _] : slot.subelementTypes)
682 usedIndices.insert(key);
684 return isa<hw::StructType, hw::ArrayType, IntegerType>(slot.valueType);
687DeletionKind DriveOp::rewire(
const DestructurableMemorySlot &slot,
688 DenseMap<Attribute, MemorySlot> &subslots,
689 OpBuilder &builder,
const DataLayout &dataLayout) {
690 SmallVector<std::pair<unsigned, Value>> driven;
693 for (
auto [idx, sig] : driven) {
694 Type nestedType = cast<RefType>(sig.getType()).getNestedType();
698 getTime(), getEnable());
701 return DeletionKind::Delete;
705DriveOp::ensureOnlySafeAccesses(
const MemorySlot &slot,
706 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
707 const DataLayout &dataLayout) {
715LogicalResult llhd::AssignOp::fold(FoldAdaptor adaptor,
716 SmallVectorImpl<OpFoldResult> &result) {
720 if (matchPattern(getEnable(), m_One())) {
721 getEnableMutable().clear();
728LogicalResult llhd::AssignOp::canonicalize(llhd::AssignOp op,
729 PatternRewriter &rewriter) {
733 if (matchPattern(op.getEnable(), m_Zero())) {
734 rewriter.eraseOp(op);
741bool AssignOp::canRewire(
const DestructurableMemorySlot &slot,
742 SmallPtrSetImpl<Attribute> &usedIndices,
743 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
744 const DataLayout &dataLayout) {
745 for (
auto [key, _] : slot.subelementTypes)
746 usedIndices.insert(key);
748 return isa<hw::StructType, hw::ArrayType, IntegerType>(slot.valueType);
751DeletionKind AssignOp::rewire(
const DestructurableMemorySlot &slot,
752 DenseMap<Attribute, MemorySlot> &subslots,
754 const DataLayout &dataLayout) {
755 SmallVector<std::pair<unsigned, Value>> assigned;
758 for (
auto [idx, sig] : assigned) {
759 Type nestedType = cast<RefType>(sig.getType()).getNestedType();
766 return DeletionKind::Delete;
770AssignOp::ensureOnlySafeAccesses(
const MemorySlot &slot,
771 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
772 const DataLayout &dataLayout) {
780LogicalResult llhd::AssignNetOp::fold(FoldAdaptor adaptor,
781 SmallVectorImpl<OpFoldResult> &result) {
785 if (matchPattern(getEnable(), m_One())) {
786 getEnableMutable().clear();
793LogicalResult llhd::AssignNetOp::canonicalize(llhd::AssignNetOp op,
794 PatternRewriter &rewriter) {
798 if (matchPattern(op.getEnable(), m_Zero())) {
799 rewriter.eraseOp(op);
806bool AssignNetOp::canRewire(
const DestructurableMemorySlot &slot,
807 SmallPtrSetImpl<Attribute> &usedIndices,
808 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
809 const DataLayout &dataLayout) {
810 for (
auto [key, _] : slot.subelementTypes)
811 usedIndices.insert(key);
813 return isa<hw::StructType, hw::ArrayType, IntegerType>(slot.valueType);
816DeletionKind AssignNetOp::rewire(
const DestructurableMemorySlot &slot,
817 DenseMap<Attribute, MemorySlot> &subslots,
819 const DataLayout &dataLayout) {
820 SmallVector<std::pair<unsigned, Value>> assigned;
823 for (
auto [idx, sig] : assigned) {
824 Type nestedType = cast<NetType>(sig.getType()).getNestedType();
831 return DeletionKind::Delete;
834LogicalResult AssignNetOp::ensureOnlySafeAccesses(
835 const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
836 const DataLayout &dataLayout) {
844LogicalResult ProcessOp::canonicalize(ProcessOp op, PatternRewriter &rewriter) {
845 if (!op.getBody().hasOneBlock())
848 auto &block = op.getBody().front();
849 auto haltOp = dyn_cast<HaltOp>(block.getTerminator());
853 if (op.getNumResults() == 0 && block.getOperations().size() == 1) {
854 rewriter.eraseOp(op);
859 if (!llvm::all_of(block.without_terminator(), [](
auto &bodyOp) {
860 return bodyOp.template hasTrait<OpTrait::ConstantLike>();
864 auto yieldOperands = haltOp.getYieldOperands();
867 llvm::BitVector operandsToErase(yieldOperands.size());
869 for (
auto [operandNo, operand] : llvm::enumerate(yieldOperands)) {
870 auto *defOp = operand.getDefiningOp();
871 if (defOp && defOp->hasTrait<OpTrait::ConstantLike>()) {
874 if (!defOp->getParentRegion()->isProperAncestor(&op.getBody())) {
875 defOp->moveBefore(op);
877 rewriter.replaceAllUsesWith(op.getResult(operandNo), operand);
878 operandsToErase.set(operandNo);
884 if (!uniqueOperands.contains(operand)) {
885 const auto newPos = uniqueOperands.size();
886 uniqueOperands.insert(std::make_pair(operand, newPos));
887 origToNewPos.insert(std::make_pair(operandNo, newPos));
889 auto firstOccurrencePos = uniqueOperands.lookup(operand);
890 origToNewPos.insert(std::make_pair(operandNo, firstOccurrencePos));
891 operandsToErase.set(operandNo);
895 const auto countOperandsToErase = operandsToErase.count();
896 if (countOperandsToErase == 0)
901 if (countOperandsToErase == op.getNumResults()) {
902 rewriter.eraseOp(op);
906 rewriter.modifyOpInPlace(haltOp,
907 [&] { haltOp->eraseOperands(operandsToErase); });
909 SmallVector<Type> resultTypes = llvm::to_vector(haltOp->getOperandTypes());
910 auto newProcessOp = ProcessOp::create(rewriter, op.getLoc(), resultTypes,
911 op->getOperands(), op->getAttrs());
912 newProcessOp.getBody().takeBody(op.getBody());
915 for (
auto oldResult : op.getResults()) {
916 auto newResultPos = origToNewPos.find(oldResult.getResultNumber());
917 if (newResultPos == origToNewPos.end())
919 auto newResult = newProcessOp.getResult(newResultPos->getSecond());
920 rewriter.replaceAllUsesWith(oldResult, newResult);
923 rewriter.eraseOp(op);
931LogicalResult CombinationalOp::canonicalize(CombinationalOp op,
932 PatternRewriter &rewriter) {
935 if (op.getBody().hasOneBlock() && isMemoryEffectFree(op)) {
936 auto &block = op.getBody().front();
937 auto *terminator = block.getTerminator();
938 rewriter.inlineBlockBefore(&block, op, ValueRange{});
939 rewriter.replaceOp(op, terminator->getOperands());
940 rewriter.eraseOp(terminator);
951 ValueRange yieldOperands) {
953 auto *parentOp = op->getParentOp();
954 SmallVector<Type> resultTypes;
955 TypeSwitch<Operation *>(parentOp)
956 .Case<ProcessOp, CombinationalOp>([&](
auto op) {
957 resultTypes.append(op.getResultTypes().begin(),
958 op.getResultTypes().end());
960 .Case<FinalOp>([](
auto) {})
961 .Case<GlobalSignalOp>(
962 [&](
auto op) { resultTypes.push_back(op.getType()); });
965 if (yieldOperands.size() != resultTypes.size())
966 return op->emitOpError()
967 <<
"has " << yieldOperands.size()
968 <<
" yield operands, but enclosing '" << parentOp->getName()
969 <<
"' returns " << resultTypes.size();
972 for (
unsigned i = 0; i < yieldOperands.size(); ++i)
973 if (yieldOperands[i].getType() != resultTypes[i])
974 return op->emitError()
975 <<
"type of yield operand " << i <<
" ("
976 << yieldOperands[i].getType() <<
") does not match enclosing '"
977 << parentOp->getName() <<
"' result type (" << resultTypes[i]
983LogicalResult WaitOp::verify() {
991LogicalResult HaltOp::verify() {
999LogicalResult YieldOp::verify() {
1004struct IntegerTypeInterface
1005 :
public DestructurableTypeInterface::ExternalModel<IntegerTypeInterface,
1007 std::optional<DenseMap<Attribute, Type>>
1021 Type getTypeAtIndex(Type type, Attribute index)
const {
1023 llvm_unreachable(
"Not implemented");
1029 registry.addExtension(+[](MLIRContext *ctx, BuiltinDialect *dialect) {
1030 IntegerType::attachInterface<IntegerTypeInterface>(*ctx);
1033 ctx->loadDialect<comb::CombDialect>();
1041LogicalResult GlobalSignalOp::verifyRegions() {
1042 if (
auto *block = getInitBlock()) {
1043 auto &terminator = block->back();
1044 if (!isa<YieldOp>(terminator))
1045 return emitOpError() <<
"must have a 'llhd.yield' terminator";
1050Block *GlobalSignalOp::getInitBlock() {
1051 if (getInitRegion().
empty())
1053 return &getInitRegion().front();
1061GetGlobalSignalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1064 symbolTable.lookupNearestSymbolFrom(*
this, getGlobalNameAttr());
1066 return emitOpError() <<
"references unknown symbol " << getGlobalNameAttr();
1069 auto signal = dyn_cast<GlobalSignalOp>(symbol);
1071 return emitOpError() <<
"must reference a 'llhd.global_signal', but "
1072 << getGlobalNameAttr() <<
" is a '"
1073 << symbol->getName() <<
"'";
1076 auto expType = signal.getType();
1077 auto actType = getType().getNestedType();
1078 if (expType != actType)
1079 return emitOpError() <<
"returns a " << actType <<
" reference, but "
1080 << getGlobalNameAttr() <<
" is of type " << expType;
1089ParseResult CoroutineOp::parse(OpAsmParser &parser, OperationState &result) {
1090 auto buildFuncType =
1091 [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,
1092 function_interface_impl::VariadicFlag,
1093 std::string &) {
return builder.getFunctionType(argTypes, results); };
1095 return function_interface_impl::parseFunctionOp(
1096 parser, result,
false,
1097 getFunctionTypeAttrName(result.name), buildFuncType,
1098 getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));
1101void CoroutineOp::print(OpAsmPrinter &p) {
1102 function_interface_impl::printFunctionOp(
1103 p, *
this,
false, getFunctionTypeAttrName(),
1104 getArgAttrsAttrName(), getResAttrsAttrName());
1112CallCoroutineOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1113 auto calleeName = getCalleeAttr();
1115 symbolTable.lookupNearestSymbolFrom<CoroutineOp>(*
this, calleeName);
1117 return emitOpError() <<
"'" << calleeName.getValue()
1118 <<
"' does not reference a valid 'llhd.coroutine'";
1120 auto type = coroutine.getFunctionType();
1121 if (type.getNumInputs() != getNumOperands())
1122 return emitOpError() <<
"has " << getNumOperands()
1123 <<
" operands, but callee expects "
1124 << type.getNumInputs();
1126 for (
unsigned i = 0, e = type.getNumInputs(); i != e; ++i)
1127 if (getOperand(i).getType() != type.getInput(i))
1128 return emitOpError() <<
"operand " << i <<
" type mismatch: expected "
1129 << type.getInput(i) <<
", got "
1130 << getOperand(i).getType();
1132 if (type.getNumResults() != getNumResults())
1133 return emitOpError() <<
"has " << getNumResults()
1134 <<
" results, but callee returns "
1135 << type.getNumResults();
1137 for (
unsigned i = 0, e = type.getNumResults(); i != e; ++i)
1138 if (getResult(i).getType() != type.getResult(i))
1139 return emitOpError() <<
"result " << i <<
" type mismatch: expected "
1140 << type.getResult(i) <<
", got "
1141 << getResult(i).getType();
1150#define GET_OP_CLASSES
1151#include "circt/Dialect/LLHD/LLHD.cpp.inc"
1152#include "circt/Dialect/LLHD/LLHDEnums.cpp.inc"
1153#include "circt/Dialect/LLHD/LLHDInterfaces.cpp.inc"
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static void getSortedPtrs(DenseMap< Attribute, MemorySlot > &subslots, SmallVectorImpl< std::pair< unsigned, Value > > &sorted)
static LogicalResult verifyYieldResults(Operation *op, ValueRange yieldOperands)
static bool hasUserOfKind(Operation *op)
static int64_t intervalOverlap(int64_t a1, int64_t a2, int64_t b1, int64_t b2)
static LogicalResult canonicalizeSigPtrArraySliceOp(Op op, PatternRewriter &rewriter)
static std::optional< DenseMap< Attribute, Type > > getIntegerSubelementIndexMap(Type type, Value value)
static std::optional< DenseMap< Attribute, Type > > getSubelementIndexMap(Type type, Value value)
static OpFoldResult foldSigPtrExtractOp(Op op, ArrayRef< Attribute > operands)
static Value getValueAtIndex(OpBuilder &builder, Location loc, Value val, unsigned index, Type resultType)
static Location getLoc(DefSlot slot)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
static InstancePath empty
create(elements, Type result_type=None)
create(elements, Type result_type=None)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
BaseTy type_dyn_cast(Type type)
unsigned getLLHDTypeWidth(Type type)
Type getLLHDElementType(Type type)
void registerDestructableIntegerExternalModel(mlir::DialectRegistry ®istry)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn