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"
26 using namespace circt;
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();
56 OpFoldResult llhd::ConstantTimeOp::fold(FoldAdaptor adaptor) {
57 assert(adaptor.getOperands().empty() &&
"const has no operands");
58 return getValueAttr();
61 void 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);
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());
94 SmallVector<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}};
108 DenseMap<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>(
134 {sigOp.getResult(), type});
140 std::optional<DestructurableAllocationOpInterface>
141 SignalOp::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();
166 OpFoldResult llhd::SigExtractOp::fold(FoldAdaptor adaptor) {
170 OpFoldResult 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();
192 OpFoldResult llhd::SigArraySliceOp::fold(FoldAdaptor adaptor) {
196 OpFoldResult 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);
227 PatternRewriter &rewriter) {
232 PatternRewriter &rewriter) {
240 bool 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)))
251 if (!slot.subelementTypes.contains(index))
253 usedIndices.insert(index);
254 mustBeSafelyUsed.emplace_back<MemorySlot>(
256 cast<hw::InOutType>(getResult().getType()).getElementType()});
260 DeletionKind SigArrayGetOp::rewire(
const DestructurableMemorySlot &slot,
261 DenseMap<Attribute, MemorySlot> &subslots,
263 const DataLayout &dataLayout) {
265 bool result = matchPattern(getIndex(), m_ConstantInt(&idx));
270 auto it = subslots.find(index);
271 assert(it != subslots.end());
272 replaceAllUsesWith(it->getSecond().ptr);
273 return DeletionKind::Delete;
276 LogicalResult SigArrayGetOp::ensureOnlySafeAccesses(
277 const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
278 const DataLayout &dataLayout) {
286 template <
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";
306 LogicalResult 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);
315 LogicalResult 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);
324 bool 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());
337 if (!slot.subelementTypes.contains(indexAttr))
339 usedIndices.insert(indexAttr);
340 mustBeSafelyUsed.emplace_back<MemorySlot>(
342 cast<hw::InOutType>(getResult().getType()).getElementType()});
347 SigStructExtractOp::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());
355 auto it = subslots.find(indexAttr);
356 assert(it != subslots.end());
357 replaceAllUsesWith(it->getSecond().ptr);
358 return DeletionKind::Delete;
361 LogicalResult 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; });
381 bool 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);
391 DeletionKind 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;
414 PrbOp::ensureOnlySafeAccesses(
const MemorySlot &slot,
415 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
416 const DataLayout &dataLayout) {
424 LogicalResult llhd::DrvOp::fold(FoldAdaptor adaptor,
425 SmallVectorImpl<OpFoldResult> &result) {
429 if (matchPattern(getEnable(), m_One())) {
430 getEnableMutable().clear();
438 PatternRewriter &rewriter) {
442 if (matchPattern(op.getEnable(), m_Zero())) {
443 rewriter.eraseOp(op);
450 bool 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);
460 DeletionKind 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;
475 DrvOp::ensureOnlySafeAccesses(
const MemorySlot &slot,
476 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
477 const DataLayout &dataLayout) {
486 SuccessorOperands llhd::WaitOp::getSuccessorOperands(
unsigned index) {
487 assert(index == 0 &&
"invalid successor index");
488 return SuccessorOperands(getDestOpsMutable());
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 OpFoldResult foldSigPtrArraySliceOp(Op op, ArrayRef< Attribute > operands)
static LogicalResult canonicalizeSigPtrArraySliceOp(Op op, PatternRewriter &rewriter)
static void getSortedPtrs(DenseMap< Attribute, MemorySlot > &subslots, SmallVectorImpl< std::pair< unsigned, Value >> &sorted)
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)
def create(data_type, value)
static LogicalResult canonicalize(Op op, PatternRewriter &rewriter)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
void getAsmResultNames(OpAsmSetValueNameFn setNameFn, StringRef instanceName, ArrayAttr resultNames, ValueRange results)
Suggest a name for each result value based on the saved result names attribute.
unsigned getLLHDTypeWidth(Type type)
Type getLLHDElementType(Type type)
circt::hw::InOutType InOutType
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn