16#include "mlir/IR/Attributes.h"
17#include "mlir/IR/BuiltinTypes.h"
18#include "mlir/IR/Matchers.h"
19#include "mlir/IR/PatternMatch.h"
20#include "mlir/IR/Region.h"
21#include "mlir/IR/Types.h"
22#include "mlir/IR/Value.h"
23#include "llvm/ADT/ArrayRef.h"
24#include "llvm/ADT/SmallVector.h"
31 if (
auto sig = dyn_cast<hw::InOutType>(type))
32 type = sig.getElementType();
33 else if (
auto ptr = dyn_cast<llhd::PtrType>(type))
34 type = ptr.getElementType();
35 if (
auto array = dyn_cast<hw::ArrayType>(type))
36 return array.getNumElements();
37 if (
auto tup = dyn_cast<hw::StructType>(type))
38 return tup.getElements().size();
39 return type.getIntOrFloatBitWidth();
43 if (
auto sig = dyn_cast<hw::InOutType>(type))
44 type = sig.getElementType();
45 else if (
auto ptr = dyn_cast<llhd::PtrType>(type))
46 type = ptr.getElementType();
47 if (
auto array = dyn_cast<hw::ArrayType>(type))
48 return array.getElementType();
56OpFoldResult llhd::ConstantTimeOp::fold(FoldAdaptor adaptor) {
57 assert(adaptor.getOperands().empty() &&
"const has no operands");
58 return getValueAttr();
61void llhd::ConstantTimeOp::build(OpBuilder &builder, OperationState &result,
62 unsigned time,
const StringRef &timeUnit,
63 unsigned delta,
unsigned epsilon) {
64 auto *ctx = builder.getContext();
65 auto attr = TimeAttr::get(ctx, time, timeUnit, delta, epsilon);
66 return build(builder, result, TimeType::get(ctx), attr);
75 return TypeSwitch<Type, Value>(val.getType())
76 .Case<hw::StructType>([&](hw::StructType ty) -> Value {
78 loc, val, ty.getElements()[index].name);
80 .Case<hw::ArrayType>([&](hw::ArrayType ty) -> Value {
83 builder.getIntegerType(llvm::Log2_64_Ceil(ty.getNumElements())),
91 setNameFn(getResult(), *
getName());
94SmallVector<DestructurableMemorySlot> SignalOp::getDestructurableSlots() {
95 auto type = getType().getElementType();
97 auto destructurable = llvm::dyn_cast<DestructurableTypeInterface>(type);
101 auto destructuredType = destructurable.getSubelementIndexMap();
102 if (!destructuredType)
105 return {DestructurableMemorySlot{{getResult(), type}, *destructuredType}};
108DenseMap<Attribute, MemorySlot> SignalOp::destructure(
109 const DestructurableMemorySlot &slot,
110 const SmallPtrSetImpl<Attribute> &usedIndices, OpBuilder &builder,
111 SmallVectorImpl<DestructurableAllocationOpInterface> &newAllocators) {
112 assert(slot.ptr == getResult());
113 builder.setInsertionPointAfter(*
this);
115 auto destructurableType =
116 cast<DestructurableTypeInterface>(getType().getElementType());
117 DenseMap<Attribute, MemorySlot> slotMap;
118 SmallVector<std::pair<unsigned, Type>> indices;
119 for (
auto attr : usedIndices) {
120 assert(isa<IntegerAttr>(attr));
121 auto elemType = destructurableType.getTypeAtIndex(attr);
122 assert(elemType &&
"used index must exist");
123 indices.push_back({cast<IntegerAttr>(attr).getInt(), elemType});
126 llvm::sort(indices, [](
auto a,
auto b) {
return a.first < b.first; });
128 for (
auto [index, type] : indices) {
130 auto sigOp = builder.create<SignalOp>(getLoc(), getNameAttr(), init);
131 newAllocators.push_back(sigOp);
132 slotMap.try_emplace<MemorySlot>(
133 IntegerAttr::get(IndexType::get(getContext()), index),
134 {sigOp.getResult(), type});
140std::optional<DestructurableAllocationOpInterface>
141SignalOp::handleDestructuringComplete(
const DestructurableMemorySlot &slot,
142 OpBuilder &builder) {
143 assert(slot.ptr == getResult());
159 if (op.getResultWidth() == op.getInputWidth() &&
160 cast<IntegerAttr>(operands[1]).getValue().isZero())
161 return op.getInput();
166OpFoldResult llhd::SigExtractOp::fold(FoldAdaptor adaptor) {
170OpFoldResult llhd::PtrExtractOp::fold(FoldAdaptor adaptor) {
180 ArrayRef<Attribute> operands) {
185 if (op.getResultWidth() == op.getInputWidth() &&
186 cast<IntegerAttr>(operands[1]).getValue().isZero())
187 return op.getInput();
192OpFoldResult llhd::SigArraySliceOp::fold(FoldAdaptor adaptor) {
196OpFoldResult llhd::PtrArraySliceOp::fold(FoldAdaptor adaptor) {
202 PatternRewriter &rewriter) {
203 IntegerAttr indexAttr;
204 if (!matchPattern(op.getLowIndex(), m_Constant(&indexAttr)))
210 if (matchPattern(op.getInput(),
211 m_Op<Op>(matchers::m_Any(), m_Constant(&a)))) {
212 auto sliceOp = op.getInput().template getDefiningOp<Op>();
213 rewriter.modifyOpInPlace(op, [&]() {
214 op.getInputMutable().assign(sliceOp.getInput());
216 op->getLoc(), a.getValue() + indexAttr.getValue());
217 op.getLowIndexMutable().assign(newIndex);
226LogicalResult llhd::SigArraySliceOp::canonicalize(llhd::SigArraySliceOp op,
227 PatternRewriter &rewriter) {
231LogicalResult llhd::PtrArraySliceOp::canonicalize(llhd::PtrArraySliceOp op,
232 PatternRewriter &rewriter) {
240bool SigArrayGetOp::canRewire(
const DestructurableMemorySlot &slot,
241 SmallPtrSetImpl<Attribute> &usedIndices,
242 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
243 const DataLayout &dataLayout) {
244 if (slot.ptr != getInput())
247 if (!matchPattern(getIndex(), m_ConstantInt(&idx)))
250 IntegerAttr::get(IndexType::get(getContext()), idx.getZExtValue());
251 if (!slot.subelementTypes.contains(index))
253 usedIndices.insert(index);
254 mustBeSafelyUsed.emplace_back<MemorySlot>(
256 cast<hw::InOutType>(getResult().getType()).getElementType()});
260DeletionKind SigArrayGetOp::rewire(
const DestructurableMemorySlot &slot,
261 DenseMap<Attribute, MemorySlot> &subslots,
263 const DataLayout &dataLayout) {
265 bool result = matchPattern(getIndex(), m_ConstantInt(&idx));
269 IntegerAttr::get(IndexType::get(getContext()), idx.getZExtValue());
270 auto it = subslots.find(index);
271 assert(it != subslots.end());
272 replaceAllUsesWith(it->getSecond().ptr);
273 return DeletionKind::Delete;
276LogicalResult SigArrayGetOp::ensureOnlySafeAccesses(
277 const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
278 const DataLayout &dataLayout) {
286template <
class OpType,
class SigPtrType>
288 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
289 DictionaryAttr attrs, mlir::OpaqueProperties properties,
290 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
291 typename OpType::Adaptor adaptor(operands, attrs, properties, regions);
293 cast<hw::StructType>(
294 cast<SigPtrType>(adaptor.getInput().getType()).getElementType())
295 .getFieldType(adaptor.getField());
297 context->getDiagEngine().emit(loc.value_or(UnknownLoc()),
298 DiagnosticSeverity::Error)
299 <<
"invalid field name specified";
302 results.push_back(SigPtrType::get(type));
306LogicalResult llhd::SigStructExtractOp::inferReturnTypes(
307 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
308 DictionaryAttr attrs, mlir::OpaqueProperties properties,
309 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
312 context, loc, operands, attrs, properties, regions, results);
315LogicalResult llhd::PtrStructExtractOp::inferReturnTypes(
316 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
317 DictionaryAttr attrs, mlir::OpaqueProperties properties,
318 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
321 context, loc, operands, attrs, properties, regions, results);
324bool SigStructExtractOp::canRewire(
325 const DestructurableMemorySlot &slot,
326 SmallPtrSetImpl<Attribute> &usedIndices,
327 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
328 const DataLayout &dataLayout) {
329 if (slot.ptr != getInput())
331 auto index = cast<hw::StructType>(
332 cast<hw::InOutType>(getInput().getType()).getElementType())
333 .getFieldIndex(getFieldAttr());
336 auto indexAttr = IntegerAttr::get(IndexType::get(getContext()), *index);
337 if (!slot.subelementTypes.contains(indexAttr))
339 usedIndices.insert(indexAttr);
340 mustBeSafelyUsed.emplace_back<MemorySlot>(
342 cast<hw::InOutType>(getResult().getType()).getElementType()});
347SigStructExtractOp::rewire(
const DestructurableMemorySlot &slot,
348 DenseMap<Attribute, MemorySlot> &subslots,
349 OpBuilder &builder,
const DataLayout &dataLayout) {
350 auto index = cast<hw::StructType>(
351 cast<hw::InOutType>(getInput().getType()).getElementType())
352 .getFieldIndex(getFieldAttr());
353 assert(index.has_value());
354 auto indexAttr = IntegerAttr::get(IndexType::get(getContext()), *index);
355 auto it = subslots.find(indexAttr);
356 assert(it != subslots.end());
357 replaceAllUsesWith(it->getSecond().ptr);
358 return DeletionKind::Delete;
361LogicalResult SigStructExtractOp::ensureOnlySafeAccesses(
362 const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
363 const DataLayout &dataLayout) {
372 SmallVectorImpl<std::pair<unsigned, Value>> &sorted) {
373 for (
auto [attr, mem] : subslots) {
374 assert(isa<IntegerAttr>(attr));
375 sorted.push_back({cast<IntegerAttr>(attr).getInt(), mem.ptr});
378 llvm::sort(sorted, [](
auto a,
auto b) {
return a.first < b.first; });
381bool PrbOp::canRewire(
const DestructurableMemorySlot &slot,
382 SmallPtrSetImpl<Attribute> &usedIndices,
383 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
384 const DataLayout &dataLayout) {
385 for (
auto [key, _] : slot.subelementTypes)
386 usedIndices.insert(key);
388 return isa<hw::StructType, hw::ArrayType>(slot.elemType);
391DeletionKind PrbOp::rewire(
const DestructurableMemorySlot &slot,
392 DenseMap<Attribute, MemorySlot> &subslots,
393 OpBuilder &builder,
const DataLayout &dataLayout) {
394 SmallVector<std::pair<unsigned, Value>> elements;
395 SmallVector<Value> probed;
397 for (
auto [_, val] : elements)
398 probed.push_back(builder.create<PrbOp>(getLoc(), val));
400 Value repl = TypeSwitch<Type, Value>(getType())
401 .Case<hw::StructType>([&](
auto ty) {
403 getLoc(), getType(), probed);
405 .Case<hw::ArrayType>([&](
auto ty) {
409 replaceAllUsesWith(repl);
410 return DeletionKind::Delete;
414PrbOp::ensureOnlySafeAccesses(
const MemorySlot &slot,
415 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
416 const DataLayout &dataLayout) {
424LogicalResult llhd::DrvOp::fold(FoldAdaptor adaptor,
425 SmallVectorImpl<OpFoldResult> &result) {
429 if (matchPattern(getEnable(), m_One())) {
430 getEnableMutable().clear();
437LogicalResult llhd::DrvOp::canonicalize(llhd::DrvOp op,
438 PatternRewriter &rewriter) {
442 if (matchPattern(op.getEnable(), m_Zero())) {
443 rewriter.eraseOp(op);
450bool DrvOp::canRewire(
const DestructurableMemorySlot &slot,
451 SmallPtrSetImpl<Attribute> &usedIndices,
452 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
453 const DataLayout &dataLayout) {
454 for (
auto [key, _] : slot.subelementTypes)
455 usedIndices.insert(key);
457 return isa<hw::StructType, hw::ArrayType>(slot.elemType);
460DeletionKind DrvOp::rewire(
const DestructurableMemorySlot &slot,
461 DenseMap<Attribute, MemorySlot> &subslots,
462 OpBuilder &builder,
const DataLayout &dataLayout) {
463 SmallVector<std::pair<unsigned, Value>> driven;
466 for (
auto [idx, sig] : driven)
467 builder.create<DrvOp>(getLoc(), sig,
469 getTime(), getEnable());
471 return DeletionKind::Delete;
475DrvOp::ensureOnlySafeAccesses(
const MemorySlot &slot,
476 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
477 const DataLayout &dataLayout) {
486SuccessorOperands llhd::WaitOp::getSuccessorOperands(
unsigned index) {
487 assert(index == 0 &&
"invalid successor index");
488 return SuccessorOperands(getDestOpsMutable());
495LogicalResult llhd::ConnectOp::canonicalize(llhd::ConnectOp op,
496 PatternRewriter &rewriter) {
497 if (op.getLhs() == op.getRhs())
498 rewriter.eraseOp(op);
502#include "circt/Dialect/LLHD/IR/LLHDEnums.cpp.inc"
504#define GET_OP_CLASSES
505#include "circt/Dialect/LLHD/IR/LLHD.cpp.inc"
assert(baseType &&"element must be base type")
static InstancePath empty
static Value getValueAtIndex(OpBuilder &builder, Location loc, Value val, unsigned index)
static void getSortedPtrs(DenseMap< Attribute, MemorySlot > &subslots, SmallVectorImpl< std::pair< unsigned, Value > > &sorted)
static OpFoldResult foldSigPtrArraySliceOp(Op op, ArrayRef< Attribute > operands)
static LogicalResult canonicalizeSigPtrArraySliceOp(Op op, PatternRewriter &rewriter)
static OpFoldResult foldSigPtrExtractOp(Op op, ArrayRef< Attribute > operands)
static LogicalResult inferReturnTypesOfStructExtractOp(MLIRContext *context, std::optional< Location > loc, ValueRange operands, DictionaryAttr attrs, mlir::OpaqueProperties properties, mlir::RegionRange regions, SmallVectorImpl< Type > &results)
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.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn