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 "llvm/ADT/ArrayRef.h"
23#include "llvm/ADT/SmallVector.h"
30 if (
auto sig = dyn_cast<RefType>(type))
31 type = sig.getNestedType();
32 if (
auto array = dyn_cast<hw::ArrayType>(type))
33 return array.getNumElements();
34 if (
auto tup = dyn_cast<hw::StructType>(type))
35 return tup.getElements().size();
36 return type.getIntOrFloatBitWidth();
40 if (
auto sig = dyn_cast<RefType>(type))
41 type = sig.getNestedType();
42 if (
auto array = dyn_cast<hw::ArrayType>(type))
43 return array.getElementType();
47template <
typename... OpTypes>
49 for (
auto *user : op->getUsers()) {
50 if (isa<OpTypes...>(user))
60OpFoldResult llhd::ConstantTimeOp::fold(FoldAdaptor adaptor) {
61 assert(adaptor.getOperands().empty() &&
"const has no operands");
62 return getValueAttr();
65void llhd::ConstantTimeOp::build(OpBuilder &builder, OperationState &result,
66 uint64_t time,
const StringRef &timeUnit,
67 unsigned delta,
unsigned epsilon) {
68 auto *ctx = builder.getContext();
69 auto attr = TimeAttr::get(ctx, time, timeUnit, delta, epsilon);
70 return build(builder, result, TimeType::get(ctx), attr);
78 unsigned index, Type resultType) {
79 return TypeSwitch<Type, Value>(val.getType())
80 .Case<hw::StructType>([&](hw::StructType ty) -> Value {
82 ty.getElements()[index].name);
84 .Case<hw::ArrayType>([&](hw::ArrayType ty) -> Value {
87 builder.getIntegerType(llvm::Log2_64_Ceil(ty.getNumElements())),
91 .Case<IntegerType>([&](IntegerType ty) -> Value {
93 resultType.getIntOrFloatBitWidth());
99 setNameFn(getResult(), *
getName());
107static std::optional<DenseMap<Attribute, Type>>
109 int width = type.getIntOrFloatBitWidth();
115 SmallVector<bool> startIndices(width,
false);
116 for (Operation *user : value.getUsers()) {
117 if (
auto extract = dyn_cast<SigExtractOp>(user)) {
119 if (matchPattern(extract.getLowBit(), m_ConstantInt(&lowBit))) {
120 startIndices[lowBit.getZExtValue()] =
true;
121 int64_t highBit = lowBit.getZExtValue() + extract.getResultWidth();
123 startIndices[highBit] =
true;
127 if (isa<ProbeOp, DriveOp>(user)) {
137 DenseMap<Attribute, Type> destructured;
138 for (
int start = 0; start < width;) {
140 while (end < width && !startIndices[end])
143 int runLength = end - start;
146 {IntegerAttr::get(IndexType::get(type.getContext()), start),
147 IntegerType::get(type.getContext(), runLength)});
154static std::optional<DenseMap<Attribute, Type>>
159 if (
auto intType = dyn_cast<IntegerType>(type)) {
162 auto destructurable = llvm::dyn_cast<DestructurableTypeInterface>(type);
165 return destructurable.getSubelementIndexMap();
169SmallVector<DestructurableMemorySlot> SignalOp::getDestructurableSlots() {
170 auto type = getType().getNestedType();
174 if (!
hasUserOfKind<SigExtractOp, SigArrayGetOp, SigStructExtractOp,
175 SigArraySliceOp>(*
this))
179 if (!destructuredType)
181 return {DestructurableMemorySlot{{getResult(), type}, *destructuredType}};
184DenseMap<Attribute, MemorySlot> SignalOp::destructure(
185 const DestructurableMemorySlot &slot,
186 const SmallPtrSetImpl<Attribute> &usedIndices, OpBuilder &builder,
187 SmallVectorImpl<DestructurableAllocationOpInterface> &newAllocators) {
188 assert(slot.ptr == getResult());
189 builder.setInsertionPointAfter(*
this);
191 DenseMap<Attribute, Type> subelementTypes = slot.subelementTypes;
192 DenseMap<Attribute, MemorySlot> slotMap;
193 SmallVector<std::pair<unsigned, Type>> indices;
194 for (
auto attr : usedIndices) {
195 assert(isa<IntegerAttr>(attr));
196 auto elemType = subelementTypes.at(attr);
197 assert(elemType &&
"used index must exist");
198 indices.push_back({cast<IntegerAttr>(attr).getInt(), elemType});
201 llvm::sort(indices, [](
auto a,
auto b) {
return a.first < b.first; });
203 for (
auto [index, type] : indices) {
205 auto sigOp = SignalOp::create(builder,
getLoc(), getNameAttr(), init);
206 newAllocators.push_back(sigOp);
207 slotMap.try_emplace<MemorySlot>(
208 IntegerAttr::get(IndexType::get(getContext()), index),
209 {sigOp.getResult(), type});
215std::optional<DestructurableAllocationOpInterface>
216SignalOp::handleDestructuringComplete(
const DestructurableMemorySlot &slot,
217 OpBuilder &builder) {
218 assert(slot.ptr == getResult());
234 if (op.getResultWidth() == op.getInputWidth() &&
235 cast<IntegerAttr>(operands[1]).getValue().isZero())
236 return op.getInput();
241OpFoldResult llhd::SigExtractOp::fold(FoldAdaptor adaptor) {
247 return std::max<int64_t>(0, std::min(a2, b2) - std::max(a1, b1));
251 SmallVectorImpl<std::pair<unsigned, Value>> &sorted) {
252 for (
auto [attr, mem] : subslots) {
253 assert(isa<IntegerAttr>(attr));
254 sorted.push_back({cast<IntegerAttr>(attr).getInt(), mem.ptr});
257 llvm::sort(sorted, [](
auto a,
auto b) {
return a.first < b.first; });
261 SmallVectorImpl<std::pair<unsigned, Type>> &sorted) {
262 for (
auto [attr, mem] : subslots) {
263 assert(isa<IntegerAttr>(attr));
264 sorted.push_back({cast<IntegerAttr>(attr).getInt(), mem});
267 llvm::sort(sorted, [](
auto a,
auto b) {
return a.first < b.first; });
270bool SigExtractOp::canRewire(
const DestructurableMemorySlot &slot,
271 SmallPtrSetImpl<Attribute> &usedIndices,
272 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
273 const DataLayout &dataLayout) {
274 if (slot.ptr != getInput())
278 if (!type.isSignlessInteger())
280 if (!matchPattern(getLowBit(), m_ConstantInt(&idx)))
286 for (Operation *user : getResult().getUsers()) {
287 if (!isa<ProbeOp, DriveOp>(user))
291 SmallVector<std::pair<unsigned, Type>> elements;
294 int64_t index = idx.getZExtValue();
296 int64_t coveredBits = 0;
297 for (
auto [start, type] : elements) {
298 int64_t subslotWidth = type.getIntOrFloatBitWidth();
303 usedIndices.insert(IntegerAttr::get(IndexType::get(getContext()), start));
304 coveredBits += overlap;
307 if (coveredBits != width)
310 mustBeSafelyUsed.emplace_back<MemorySlot>({getResult(), type});
314DeletionKind SigExtractOp::rewire(
const DestructurableMemorySlot &slot,
315 DenseMap<Attribute, MemorySlot> &subslots,
317 const DataLayout &dataLayout) {
319 [[maybe_unused]]
bool result = matchPattern(getLowBit(), m_ConstantInt(&idx));
322 int64_t idxVal = idx.getZExtValue();
324 SmallVector<std::pair<unsigned, Value>> elements;
327 for (Operation *user :
llvm::make_early_inc_range(getResult().getUsers())) {
328 builder.setInsertionPoint(user);
330 if (
auto probeOp = dyn_cast<ProbeOp>(user)) {
331 SmallVector<Value> values;
332 for (
auto [start, value] : elements) {
333 int64_t subslotWidth = cast<RefType>(value.getType())
335 .getIntOrFloatBitWidth();
337 start + subslotWidth);
340 values.push_back(ProbeOp::create(builder, probeOp.getLoc(), value));
342 std::reverse(values.begin(), values.end());
343 Value value = comb::ConcatOp::create(builder, probeOp.getLoc(), values);
344 probeOp.replaceAllUsesWith(value);
350 auto driveOp = cast<DriveOp>(user);
351 for (
auto [start, sig] : elements) {
352 int64_t subslotWidth =
353 cast<RefType>(sig.getType()).getNestedType().getIntOrFloatBitWidth();
360 start - idxVal, subslotWidth);
361 DriveOp::create(builder, driveOp.getLoc(), sig, val, driveOp.getTime(),
362 driveOp.getEnable());
367 return DeletionKind::Delete;
370LogicalResult SigExtractOp::ensureOnlySafeAccesses(
371 const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
372 const DataLayout &dataLayout) {
380OpFoldResult llhd::SigArraySliceOp::fold(FoldAdaptor adaptor) {
381 auto lowIndex = dyn_cast_or_null<IntegerAttr>(adaptor.getLowIndex());
386 if (getResultWidth() == getInputWidth() && lowIndex.getValue().isZero())
394 PatternRewriter &rewriter) {
395 IntegerAttr indexAttr;
396 if (!matchPattern(op.getLowIndex(), m_Constant(&indexAttr)))
402 if (matchPattern(op.getInput(),
403 m_Op<Op>(matchers::m_Any(), m_Constant(&a)))) {
404 auto sliceOp = op.getInput().template getDefiningOp<Op>();
405 rewriter.modifyOpInPlace(op, [&]() {
406 op.getInputMutable().assign(sliceOp.getInput());
408 rewriter, op->getLoc(), a.getValue() + indexAttr.getValue());
409 op.getLowIndexMutable().assign(newIndex);
418LogicalResult llhd::SigArraySliceOp::canonicalize(llhd::SigArraySliceOp op,
419 PatternRewriter &rewriter) {
427bool SigArrayGetOp::canRewire(
const DestructurableMemorySlot &slot,
428 SmallPtrSetImpl<Attribute> &usedIndices,
429 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
430 const DataLayout &dataLayout) {
431 if (slot.ptr != getInput())
434 if (!matchPattern(getIndex(), m_ConstantInt(&idx)))
437 IntegerAttr::get(IndexType::get(getContext()), idx.getZExtValue());
438 if (!slot.subelementTypes.contains(index))
440 usedIndices.insert(index);
441 mustBeSafelyUsed.emplace_back<MemorySlot>(
442 {getResult(), cast<RefType>(getResult().getType()).getNestedType()});
446DeletionKind SigArrayGetOp::rewire(
const DestructurableMemorySlot &slot,
447 DenseMap<Attribute, MemorySlot> &subslots,
449 const DataLayout &dataLayout) {
451 bool result = matchPattern(getIndex(), m_ConstantInt(&idx));
455 IntegerAttr::get(IndexType::get(getContext()), idx.getZExtValue());
456 auto it = subslots.find(index);
457 assert(it != subslots.end());
458 replaceAllUsesWith(it->getSecond().ptr);
459 return DeletionKind::Delete;
462LogicalResult SigArrayGetOp::ensureOnlySafeAccesses(
463 const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
464 const DataLayout &dataLayout) {
472LogicalResult llhd::SigStructExtractOp::inferReturnTypes(
473 MLIRContext *
context, std::optional<Location> loc, ValueRange operands,
474 DictionaryAttr attrs, mlir::OpaqueProperties properties,
475 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
476 typename SigStructExtractOp::Adaptor adaptor(operands, attrs, properties,
478 auto nestedType = cast<RefType>(adaptor.getInput().getType()).getNestedType();
482 if (
auto structType = dyn_cast<hw::StructType>(nestedType)) {
483 fieldType = structType.getFieldType(adaptor.getField());
484 }
else if (
auto unionType = dyn_cast<hw::UnionType>(nestedType)) {
485 fieldType = unionType.getFieldType(adaptor.getField());
487 context->getDiagEngine().emit(loc.value_or(UnknownLoc()),
488 DiagnosticSeverity::Error)
489 <<
"expected struct or union type";
494 context->getDiagEngine().emit(loc.value_or(UnknownLoc()),
495 DiagnosticSeverity::Error)
496 <<
"invalid field name specified";
499 results.push_back(RefType::get(fieldType));
503bool SigStructExtractOp::canRewire(
504 const DestructurableMemorySlot &slot,
505 SmallPtrSetImpl<Attribute> &usedIndices,
506 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
507 const DataLayout &dataLayout) {
508 if (slot.ptr != getInput())
511 auto nestedType = cast<RefType>(getInput().getType()).getNestedType();
512 std::optional<uint32_t> index;
515 if (
auto structType = dyn_cast<hw::StructType>(nestedType))
516 index = structType.getFieldIndex(getFieldAttr());
517 else if (
auto unionType = dyn_cast<hw::UnionType>(nestedType))
518 index = unionType.getFieldIndex(getFieldAttr());
524 auto indexAttr = IntegerAttr::get(IndexType::get(getContext()), *index);
525 if (!slot.subelementTypes.contains(indexAttr))
527 usedIndices.insert(indexAttr);
528 mustBeSafelyUsed.emplace_back<MemorySlot>(
529 {getResult(), cast<RefType>(getResult().getType()).getNestedType()});
534SigStructExtractOp::rewire(
const DestructurableMemorySlot &slot,
535 DenseMap<Attribute, MemorySlot> &subslots,
536 OpBuilder &builder,
const DataLayout &dataLayout) {
538 cast<hw::StructType>(cast<RefType>(getInput().getType()).getNestedType())
539 .getFieldIndex(getFieldAttr());
540 assert(index.has_value());
541 auto indexAttr = IntegerAttr::get(IndexType::get(getContext()), *index);
542 auto it = subslots.find(indexAttr);
543 assert(it != subslots.end());
544 replaceAllUsesWith(it->getSecond().ptr);
545 return DeletionKind::Delete;
548LogicalResult SigStructExtractOp::ensureOnlySafeAccesses(
549 const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
550 const DataLayout &dataLayout) {
558bool ProbeOp::canRewire(
const DestructurableMemorySlot &slot,
559 SmallPtrSetImpl<Attribute> &usedIndices,
560 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
561 const DataLayout &dataLayout) {
562 for (
auto [key, _] : slot.subelementTypes)
563 usedIndices.insert(key);
565 return isa<hw::StructType, hw::ArrayType, IntegerType>(slot.elemType);
568DeletionKind ProbeOp::rewire(
const DestructurableMemorySlot &slot,
569 DenseMap<Attribute, MemorySlot> &subslots,
570 OpBuilder &builder,
const DataLayout &dataLayout) {
571 SmallVector<std::pair<unsigned, Value>> elements;
572 SmallVector<Value> probed;
574 for (
auto [_, val] : elements)
575 probed.push_back(ProbeOp::create(builder,
getLoc(), val));
578 TypeSwitch<Type, Value>(getType())
579 .Case<hw::StructType>([&](
auto ty) {
583 .Case<hw::ArrayType>([&](
auto ty) {
584 std::reverse(probed.begin(), probed.end());
587 .Case<IntegerType>([&](
auto ty) {
588 std::reverse(probed.begin(), probed.end());
589 return comb::ConcatOp::create(builder,
getLoc(), probed);
592 replaceAllUsesWith(repl);
593 return DeletionKind::Delete;
597ProbeOp::ensureOnlySafeAccesses(
const MemorySlot &slot,
598 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
599 const DataLayout &dataLayout) {
603void ProbeOp::getEffects(
604 SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
606 if (mayHaveSSADominance(*getOperation()->getParentRegion()))
607 effects.emplace_back(MemoryEffects::Read::get(), &getSignalMutable());
614LogicalResult llhd::DriveOp::fold(FoldAdaptor adaptor,
615 SmallVectorImpl<OpFoldResult> &result) {
619 if (matchPattern(getEnable(), m_One())) {
620 getEnableMutable().clear();
627LogicalResult llhd::DriveOp::canonicalize(llhd::DriveOp op,
628 PatternRewriter &rewriter) {
632 if (matchPattern(op.getEnable(), m_Zero())) {
633 rewriter.eraseOp(op);
640bool DriveOp::canRewire(
const DestructurableMemorySlot &slot,
641 SmallPtrSetImpl<Attribute> &usedIndices,
642 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
643 const DataLayout &dataLayout) {
644 for (
auto [key, _] : slot.subelementTypes)
645 usedIndices.insert(key);
647 return isa<hw::StructType, hw::ArrayType, IntegerType>(slot.elemType);
650DeletionKind DriveOp::rewire(
const DestructurableMemorySlot &slot,
651 DenseMap<Attribute, MemorySlot> &subslots,
652 OpBuilder &builder,
const DataLayout &dataLayout) {
653 SmallVector<std::pair<unsigned, Value>> driven;
656 for (
auto [idx, sig] : driven) {
657 Type nestedType = cast<RefType>(sig.getType()).getNestedType();
661 getTime(), getEnable());
664 return DeletionKind::Delete;
668DriveOp::ensureOnlySafeAccesses(
const MemorySlot &slot,
669 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
670 const DataLayout &dataLayout) {
678LogicalResult ProcessOp::canonicalize(ProcessOp op, PatternRewriter &rewriter) {
679 if (!op.getBody().hasOneBlock())
682 auto &block = op.getBody().front();
683 auto haltOp = dyn_cast<HaltOp>(block.getTerminator());
687 if (op.getNumResults() == 0 && block.getOperations().size() == 1) {
688 rewriter.eraseOp(op);
693 if (!llvm::all_of(block.without_terminator(), [](
auto &bodyOp) {
694 return bodyOp.template hasTrait<OpTrait::ConstantLike>();
698 auto yieldOperands = haltOp.getYieldOperands();
701 llvm::BitVector operandsToErase(yieldOperands.size());
703 for (
auto [operandNo, operand] :
llvm::enumerate(yieldOperands)) {
704 auto *defOp = operand.getDefiningOp();
705 if (defOp && defOp->hasTrait<OpTrait::ConstantLike>()) {
708 if (!defOp->getParentRegion()->isProperAncestor(&op.getBody())) {
709 defOp->moveBefore(op);
711 rewriter.replaceAllUsesWith(op.getResult(operandNo), operand);
712 operandsToErase.set(operandNo);
718 if (!uniqueOperands.contains(operand)) {
719 const auto newPos = uniqueOperands.size();
720 uniqueOperands.insert(std::make_pair(operand, newPos));
721 origToNewPos.insert(std::make_pair(operandNo, newPos));
723 auto firstOccurrencePos = uniqueOperands.lookup(operand);
724 origToNewPos.insert(std::make_pair(operandNo, firstOccurrencePos));
725 operandsToErase.set(operandNo);
729 const auto countOperandsToErase = operandsToErase.count();
730 if (countOperandsToErase == 0)
735 if (countOperandsToErase == op.getNumResults()) {
736 rewriter.eraseOp(op);
740 rewriter.modifyOpInPlace(haltOp,
741 [&] { haltOp->eraseOperands(operandsToErase); });
743 SmallVector<Type> resultTypes = llvm::to_vector(haltOp->getOperandTypes());
744 auto newProcessOp = ProcessOp::create(rewriter, op.getLoc(), resultTypes,
745 op->getOperands(), op->getAttrs());
746 newProcessOp.getBody().takeBody(op.getBody());
749 for (
auto oldResult : op.getResults()) {
750 auto newResultPos = origToNewPos.find(oldResult.getResultNumber());
751 if (newResultPos == origToNewPos.end())
753 auto newResult = newProcessOp.getResult(newResultPos->getSecond());
754 rewriter.replaceAllUsesWith(oldResult, newResult);
757 rewriter.eraseOp(op);
765LogicalResult CombinationalOp::canonicalize(CombinationalOp op,
766 PatternRewriter &rewriter) {
769 if (op.getBody().hasOneBlock() && isMemoryEffectFree(op)) {
770 auto &block = op.getBody().front();
771 auto *terminator = block.getTerminator();
772 rewriter.inlineBlockBefore(&block, op, ValueRange{});
773 rewriter.replaceOp(op, terminator->getOperands());
774 rewriter.eraseOp(terminator);
785 ValueRange yieldOperands) {
787 auto *parentOp = op->getParentOp();
788 SmallVector<Type> resultTypes;
789 TypeSwitch<Operation *>(parentOp)
790 .Case<ProcessOp, CombinationalOp>([&](
auto op) {
791 resultTypes.append(op.getResultTypes().begin(),
792 op.getResultTypes().end());
794 .Case<FinalOp>([](
auto) {})
795 .Case<GlobalSignalOp>(
796 [&](
auto op) { resultTypes.push_back(op.getType()); });
799 if (yieldOperands.size() != resultTypes.size())
800 return op->emitOpError()
801 <<
"has " << yieldOperands.size()
802 <<
" yield operands, but enclosing '" << parentOp->getName()
803 <<
"' returns " << resultTypes.size();
806 for (
unsigned i = 0; i < yieldOperands.size(); ++i)
807 if (yieldOperands[i].getType() != resultTypes[i])
808 return op->emitError()
809 <<
"type of yield operand " << i <<
" ("
810 << yieldOperands[i].getType() <<
") does not match enclosing '"
811 << parentOp->getName() <<
"' result type (" << resultTypes[i]
817LogicalResult WaitOp::verify() {
825LogicalResult HaltOp::verify() {
833LogicalResult YieldOp::verify() {
838struct IntegerTypeInterface
839 :
public DestructurableTypeInterface::ExternalModel<IntegerTypeInterface,
841 std::optional<DenseMap<Attribute, Type>>
855 Type getTypeAtIndex(Type type, Attribute index)
const {
857 llvm_unreachable(
"Not implemented");
863 registry.addExtension(+[](MLIRContext *ctx, BuiltinDialect *dialect) {
864 IntegerType::attachInterface<IntegerTypeInterface>(*ctx);
867 ctx->loadDialect<comb::CombDialect>();
875LogicalResult GlobalSignalOp::verifyRegions() {
876 if (
auto *block = getInitBlock()) {
877 auto &terminator = block->back();
878 if (!isa<YieldOp>(terminator))
879 return emitOpError() <<
"must have a 'llhd.yield' terminator";
884Block *GlobalSignalOp::getInitBlock() {
885 if (getInitRegion().
empty())
887 return &getInitRegion().front();
895GetGlobalSignalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
898 symbolTable.lookupNearestSymbolFrom(*
this, getGlobalNameAttr());
900 return emitOpError() <<
"references unknown symbol " << getGlobalNameAttr();
903 auto signal = dyn_cast<GlobalSignalOp>(symbol);
905 return emitOpError() <<
"must reference a 'llhd.global_signal', but "
906 << getGlobalNameAttr() <<
" is a '"
907 << symbol->getName() <<
"'";
910 auto expType = signal.getType();
911 auto actType = getType().getNestedType();
912 if (expType != actType)
913 return emitOpError() <<
"returns a " << actType <<
" reference, but "
914 << getGlobalNameAttr() <<
" is of type " << expType;
923#define GET_OP_CLASSES
924#include "circt/Dialect/LLHD/LLHD.cpp.inc"
925#include "circt/Dialect/LLHD/LLHDEnums.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)
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.
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