CIRCT 22.0.0git
Loading...
Searching...
No Matches
LLHDOps.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
12#include "mlir/IR/Attributes.h"
13#include "mlir/IR/BuiltinTypes.h"
14#include "mlir/IR/Matchers.h"
15#include "mlir/IR/PatternMatch.h"
16#include "mlir/IR/Region.h"
17#include "mlir/IR/Types.h"
18#include "mlir/IR/Value.h"
19#include "llvm/ADT/ArrayRef.h"
20#include "llvm/ADT/SmallVector.h"
21
22using namespace circt;
23using namespace mlir;
24using namespace llhd;
25
26unsigned circt::llhd::getLLHDTypeWidth(Type type) {
27 if (auto sig = dyn_cast<hw::InOutType>(type))
28 type = sig.getElementType();
29 else if (auto ptr = dyn_cast<llhd::PtrType>(type))
30 type = ptr.getElementType();
31 if (auto array = dyn_cast<hw::ArrayType>(type))
32 return array.getNumElements();
33 if (auto tup = dyn_cast<hw::StructType>(type))
34 return tup.getElements().size();
35 return type.getIntOrFloatBitWidth();
36}
37
39 if (auto sig = dyn_cast<hw::InOutType>(type))
40 type = sig.getElementType();
41 else if (auto ptr = dyn_cast<llhd::PtrType>(type))
42 type = ptr.getElementType();
43 if (auto array = dyn_cast<hw::ArrayType>(type))
44 return array.getElementType();
45 return type;
46}
47
48//===----------------------------------------------------------------------===//
49// ConstantTimeOp
50//===----------------------------------------------------------------------===//
51
52OpFoldResult llhd::ConstantTimeOp::fold(FoldAdaptor adaptor) {
53 assert(adaptor.getOperands().empty() && "const has no operands");
54 return getValueAttr();
55}
56
57void llhd::ConstantTimeOp::build(OpBuilder &builder, OperationState &result,
58 uint64_t time, const StringRef &timeUnit,
59 unsigned delta, unsigned epsilon) {
60 auto *ctx = builder.getContext();
61 auto attr = TimeAttr::get(ctx, time, timeUnit, delta, epsilon);
62 return build(builder, result, TimeType::get(ctx), attr);
63}
64
65//===----------------------------------------------------------------------===//
66// SignalOp
67//===----------------------------------------------------------------------===//
68
69static Value getValueAtIndex(OpBuilder &builder, Location loc, Value val,
70 unsigned index) {
71 return TypeSwitch<Type, Value>(val.getType())
72 .Case<hw::StructType>([&](hw::StructType ty) -> Value {
73 return hw::StructExtractOp::create(builder, loc, val,
74 ty.getElements()[index].name);
75 })
76 .Case<hw::ArrayType>([&](hw::ArrayType ty) -> Value {
77 Value idx = hw::ConstantOp::create(
78 builder, loc,
79 builder.getIntegerType(llvm::Log2_64_Ceil(ty.getNumElements())),
80 index);
81 return hw::ArrayGetOp::create(builder, loc, val, idx);
82 });
83}
84
85void SignalOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
86 if (getName() && !getName()->empty())
87 setNameFn(getResult(), *getName());
88}
89
90SmallVector<DestructurableMemorySlot> SignalOp::getDestructurableSlots() {
91 auto type = getType().getElementType();
92
93 auto destructurable = llvm::dyn_cast<DestructurableTypeInterface>(type);
94 if (!destructurable)
95 return {};
96
97 auto destructuredType = destructurable.getSubelementIndexMap();
98 if (!destructuredType)
99 return {};
100
101 return {DestructurableMemorySlot{{getResult(), type}, *destructuredType}};
102}
103
104DenseMap<Attribute, MemorySlot> SignalOp::destructure(
105 const DestructurableMemorySlot &slot,
106 const SmallPtrSetImpl<Attribute> &usedIndices, OpBuilder &builder,
107 SmallVectorImpl<DestructurableAllocationOpInterface> &newAllocators) {
108 assert(slot.ptr == getResult());
109 builder.setInsertionPointAfter(*this);
110
111 auto destructurableType =
112 cast<DestructurableTypeInterface>(getType().getElementType());
113 DenseMap<Attribute, MemorySlot> slotMap;
114 SmallVector<std::pair<unsigned, Type>> indices;
115 for (auto attr : usedIndices) {
116 assert(isa<IntegerAttr>(attr));
117 auto elemType = destructurableType.getTypeAtIndex(attr);
118 assert(elemType && "used index must exist");
119 indices.push_back({cast<IntegerAttr>(attr).getInt(), elemType});
120 }
121
122 llvm::sort(indices, [](auto a, auto b) { return a.first < b.first; });
123
124 for (auto [index, type] : indices) {
125 Value init = getValueAtIndex(builder, getLoc(), getInit(), index);
126 auto sigOp = SignalOp::create(builder, getLoc(), getNameAttr(), init);
127 newAllocators.push_back(sigOp);
128 slotMap.try_emplace<MemorySlot>(
129 IntegerAttr::get(IndexType::get(getContext()), index),
130 {sigOp.getResult(), type});
131 }
132
133 return slotMap;
134}
135
136std::optional<DestructurableAllocationOpInterface>
137SignalOp::handleDestructuringComplete(const DestructurableMemorySlot &slot,
138 OpBuilder &builder) {
139 assert(slot.ptr == getResult());
140 this->erase();
141 return std::nullopt;
142}
143
144//===----------------------------------------------------------------------===//
145// SigExtractOp and PtrExtractOp
146//===----------------------------------------------------------------------===//
147
148template <class Op>
149static OpFoldResult foldSigPtrExtractOp(Op op, ArrayRef<Attribute> operands) {
150
151 if (!operands[1])
152 return nullptr;
153
154 // llhd.sig.extract(input, 0) with inputWidth == resultWidth => input
155 if (op.getResultWidth() == op.getInputWidth() &&
156 cast<IntegerAttr>(operands[1]).getValue().isZero())
157 return op.getInput();
158
159 return nullptr;
160}
161
162OpFoldResult llhd::SigExtractOp::fold(FoldAdaptor adaptor) {
163 return foldSigPtrExtractOp(*this, adaptor.getOperands());
164}
165
166OpFoldResult llhd::PtrExtractOp::fold(FoldAdaptor adaptor) {
167 return foldSigPtrExtractOp(*this, adaptor.getOperands());
168}
169
170//===----------------------------------------------------------------------===//
171// SigArraySliceOp and PtrArraySliceOp
172//===----------------------------------------------------------------------===//
173
174template <class Op>
175static OpFoldResult foldSigPtrArraySliceOp(Op op,
176 ArrayRef<Attribute> operands) {
177 if (!operands[1])
178 return nullptr;
179
180 // llhd.sig.array_slice(input, 0) with inputWidth == resultWidth => input
181 if (op.getResultWidth() == op.getInputWidth() &&
182 cast<IntegerAttr>(operands[1]).getValue().isZero())
183 return op.getInput();
184
185 return nullptr;
186}
187
188OpFoldResult llhd::SigArraySliceOp::fold(FoldAdaptor adaptor) {
189 return foldSigPtrArraySliceOp(*this, adaptor.getOperands());
190}
191
192OpFoldResult llhd::PtrArraySliceOp::fold(FoldAdaptor adaptor) {
193 return foldSigPtrArraySliceOp(*this, adaptor.getOperands());
194}
195
196template <class Op>
197static LogicalResult canonicalizeSigPtrArraySliceOp(Op op,
198 PatternRewriter &rewriter) {
199 IntegerAttr indexAttr;
200 if (!matchPattern(op.getLowIndex(), m_Constant(&indexAttr)))
201 return failure();
202
203 // llhd.sig.array_slice(llhd.sig.array_slice(target, a), b)
204 // => llhd.sig.array_slice(target, a+b)
205 IntegerAttr a;
206 if (matchPattern(op.getInput(),
207 m_Op<Op>(matchers::m_Any(), m_Constant(&a)))) {
208 auto sliceOp = op.getInput().template getDefiningOp<Op>();
209 rewriter.modifyOpInPlace(op, [&]() {
210 op.getInputMutable().assign(sliceOp.getInput());
211 Value newIndex = hw::ConstantOp::create(
212 rewriter, op->getLoc(), a.getValue() + indexAttr.getValue());
213 op.getLowIndexMutable().assign(newIndex);
214 });
215
216 return success();
217 }
218
219 return failure();
220}
221
222LogicalResult llhd::SigArraySliceOp::canonicalize(llhd::SigArraySliceOp op,
223 PatternRewriter &rewriter) {
224 return canonicalizeSigPtrArraySliceOp(op, rewriter);
225}
226
227LogicalResult llhd::PtrArraySliceOp::canonicalize(llhd::PtrArraySliceOp op,
228 PatternRewriter &rewriter) {
229 return canonicalizeSigPtrArraySliceOp(op, rewriter);
230}
231
232//===----------------------------------------------------------------------===//
233// SigArrayGetOp
234//===----------------------------------------------------------------------===//
235
236bool SigArrayGetOp::canRewire(const DestructurableMemorySlot &slot,
237 SmallPtrSetImpl<Attribute> &usedIndices,
238 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
239 const DataLayout &dataLayout) {
240 if (slot.ptr != getInput())
241 return false;
242 APInt idx;
243 if (!matchPattern(getIndex(), m_ConstantInt(&idx)))
244 return false;
245 auto index =
246 IntegerAttr::get(IndexType::get(getContext()), idx.getZExtValue());
247 if (!slot.subelementTypes.contains(index))
248 return false;
249 usedIndices.insert(index);
250 mustBeSafelyUsed.emplace_back<MemorySlot>(
251 {getResult(),
252 cast<hw::InOutType>(getResult().getType()).getElementType()});
253 return true;
254}
255
256DeletionKind SigArrayGetOp::rewire(const DestructurableMemorySlot &slot,
257 DenseMap<Attribute, MemorySlot> &subslots,
258 OpBuilder &builder,
259 const DataLayout &dataLayout) {
260 APInt idx;
261 bool result = matchPattern(getIndex(), m_ConstantInt(&idx));
262 (void)result;
263 assert(result);
264 auto index =
265 IntegerAttr::get(IndexType::get(getContext()), idx.getZExtValue());
266 auto it = subslots.find(index);
267 assert(it != subslots.end());
268 replaceAllUsesWith(it->getSecond().ptr);
269 return DeletionKind::Delete;
270}
271
272LogicalResult SigArrayGetOp::ensureOnlySafeAccesses(
273 const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
274 const DataLayout &dataLayout) {
275 return success();
276}
277
278//===----------------------------------------------------------------------===//
279// SigStructExtractOp and PtrStructExtractOp
280//===----------------------------------------------------------------------===//
281
282template <class OpType, class SigPtrType>
284 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
285 DictionaryAttr attrs, mlir::OpaqueProperties properties,
286 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
287 typename OpType::Adaptor adaptor(operands, attrs, properties, regions);
288 Type type =
289 cast<hw::StructType>(
290 cast<SigPtrType>(adaptor.getInput().getType()).getElementType())
291 .getFieldType(adaptor.getField());
292 if (!type) {
293 context->getDiagEngine().emit(loc.value_or(UnknownLoc()),
294 DiagnosticSeverity::Error)
295 << "invalid field name specified";
296 return failure();
297 }
298 results.push_back(SigPtrType::get(type));
299 return success();
300}
301
302LogicalResult llhd::SigStructExtractOp::inferReturnTypes(
303 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
304 DictionaryAttr attrs, mlir::OpaqueProperties properties,
305 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
306 return inferReturnTypesOfStructExtractOp<llhd::SigStructExtractOp,
307 hw::InOutType>(
308 context, loc, operands, attrs, properties, regions, results);
309}
310
311LogicalResult llhd::PtrStructExtractOp::inferReturnTypes(
312 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
313 DictionaryAttr attrs, mlir::OpaqueProperties properties,
314 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
315 return inferReturnTypesOfStructExtractOp<llhd::PtrStructExtractOp,
316 llhd::PtrType>(
317 context, loc, operands, attrs, properties, regions, results);
318}
319
320bool SigStructExtractOp::canRewire(
321 const DestructurableMemorySlot &slot,
322 SmallPtrSetImpl<Attribute> &usedIndices,
323 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
324 const DataLayout &dataLayout) {
325 if (slot.ptr != getInput())
326 return false;
327 auto index = cast<hw::StructType>(
328 cast<hw::InOutType>(getInput().getType()).getElementType())
329 .getFieldIndex(getFieldAttr());
330 if (!index)
331 return false;
332 auto indexAttr = IntegerAttr::get(IndexType::get(getContext()), *index);
333 if (!slot.subelementTypes.contains(indexAttr))
334 return false;
335 usedIndices.insert(indexAttr);
336 mustBeSafelyUsed.emplace_back<MemorySlot>(
337 {getResult(),
338 cast<hw::InOutType>(getResult().getType()).getElementType()});
339 return true;
340}
341
342DeletionKind
343SigStructExtractOp::rewire(const DestructurableMemorySlot &slot,
344 DenseMap<Attribute, MemorySlot> &subslots,
345 OpBuilder &builder, const DataLayout &dataLayout) {
346 auto index = cast<hw::StructType>(
347 cast<hw::InOutType>(getInput().getType()).getElementType())
348 .getFieldIndex(getFieldAttr());
349 assert(index.has_value());
350 auto indexAttr = IntegerAttr::get(IndexType::get(getContext()), *index);
351 auto it = subslots.find(indexAttr);
352 assert(it != subslots.end());
353 replaceAllUsesWith(it->getSecond().ptr);
354 return DeletionKind::Delete;
355}
356
357LogicalResult SigStructExtractOp::ensureOnlySafeAccesses(
358 const MemorySlot &slot, SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
359 const DataLayout &dataLayout) {
360 return success();
361}
362
363//===----------------------------------------------------------------------===//
364// PrbOp
365//===----------------------------------------------------------------------===//
366
367static void getSortedPtrs(DenseMap<Attribute, MemorySlot> &subslots,
368 SmallVectorImpl<std::pair<unsigned, Value>> &sorted) {
369 for (auto [attr, mem] : subslots) {
370 assert(isa<IntegerAttr>(attr));
371 sorted.push_back({cast<IntegerAttr>(attr).getInt(), mem.ptr});
372 }
373
374 llvm::sort(sorted, [](auto a, auto b) { return a.first < b.first; });
375}
376
377bool PrbOp::canRewire(const DestructurableMemorySlot &slot,
378 SmallPtrSetImpl<Attribute> &usedIndices,
379 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
380 const DataLayout &dataLayout) {
381 for (auto [key, _] : slot.subelementTypes)
382 usedIndices.insert(key);
383
384 return isa<hw::StructType, hw::ArrayType>(slot.elemType);
385}
386
387DeletionKind PrbOp::rewire(const DestructurableMemorySlot &slot,
388 DenseMap<Attribute, MemorySlot> &subslots,
389 OpBuilder &builder, const DataLayout &dataLayout) {
390 SmallVector<std::pair<unsigned, Value>> elements;
391 SmallVector<Value> probed;
392 getSortedPtrs(subslots, elements);
393 for (auto [_, val] : elements)
394 probed.push_back(PrbOp::create(builder, getLoc(), val));
395
396 Value repl =
397 TypeSwitch<Type, Value>(getType())
398 .Case<hw::StructType>([&](auto ty) {
399 return hw::StructCreateOp::create(builder, getLoc(), getType(),
400 probed);
401 })
402 .Case<hw::ArrayType>([&](auto ty) {
403 return hw::ArrayCreateOp::create(builder, getLoc(), probed);
404 });
405
406 replaceAllUsesWith(repl);
407 return DeletionKind::Delete;
408}
409
410LogicalResult
411PrbOp::ensureOnlySafeAccesses(const MemorySlot &slot,
412 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
413 const DataLayout &dataLayout) {
414 return success();
415}
416
417void PrbOp::getEffects(
418 SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
419 &effects) {
420 if (mayHaveSSADominance(*getOperation()->getParentRegion()))
421 effects.emplace_back(MemoryEffects::Read::get(), &getSignalMutable());
422}
423
424//===----------------------------------------------------------------------===//
425// DrvOp
426//===----------------------------------------------------------------------===//
427
428LogicalResult llhd::DrvOp::fold(FoldAdaptor adaptor,
429 SmallVectorImpl<OpFoldResult> &result) {
430 if (!getEnable())
431 return failure();
432
433 if (matchPattern(getEnable(), m_One())) {
434 getEnableMutable().clear();
435 return success();
436 }
437
438 return failure();
439}
440
441LogicalResult llhd::DrvOp::canonicalize(llhd::DrvOp op,
442 PatternRewriter &rewriter) {
443 if (!op.getEnable())
444 return failure();
445
446 if (matchPattern(op.getEnable(), m_Zero())) {
447 rewriter.eraseOp(op);
448 return success();
449 }
450
451 return failure();
452}
453
454bool DrvOp::canRewire(const DestructurableMemorySlot &slot,
455 SmallPtrSetImpl<Attribute> &usedIndices,
456 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
457 const DataLayout &dataLayout) {
458 for (auto [key, _] : slot.subelementTypes)
459 usedIndices.insert(key);
460
461 return isa<hw::StructType, hw::ArrayType>(slot.elemType);
462}
463
464DeletionKind DrvOp::rewire(const DestructurableMemorySlot &slot,
465 DenseMap<Attribute, MemorySlot> &subslots,
466 OpBuilder &builder, const DataLayout &dataLayout) {
467 SmallVector<std::pair<unsigned, Value>> driven;
468 getSortedPtrs(subslots, driven);
469
470 for (auto [idx, sig] : driven)
471 DrvOp::create(builder, getLoc(), sig,
472 getValueAtIndex(builder, getLoc(), getValue(), idx),
473 getTime(), getEnable());
474
475 return DeletionKind::Delete;
476}
477
478LogicalResult
479DrvOp::ensureOnlySafeAccesses(const MemorySlot &slot,
480 SmallVectorImpl<MemorySlot> &mustBeSafelyUsed,
481 const DataLayout &dataLayout) {
482 return success();
483}
484
485//===----------------------------------------------------------------------===//
486// ProcessOp
487//===----------------------------------------------------------------------===//
488
489LogicalResult ProcessOp::canonicalize(ProcessOp op, PatternRewriter &rewriter) {
490 if (!op.getBody().hasOneBlock())
491 return failure();
492
493 auto &block = op.getBody().front();
494 auto haltOp = dyn_cast<HaltOp>(block.getTerminator());
495 if (!haltOp)
496 return failure();
497
498 if (op.getNumResults() == 0 && block.getOperations().size() == 1) {
499 rewriter.eraseOp(op);
500 return success();
501 }
502
503 // Only constants and halt terminator are expected in a single block.
504 if (!llvm::all_of(block.without_terminator(), [](auto &bodyOp) {
505 return bodyOp.template hasTrait<OpTrait::ConstantLike>();
506 }))
507 return failure();
508
509 auto yieldOperands = haltOp.getYieldOperands();
512 llvm::BitVector operandsToErase(yieldOperands.size());
513
514 for (auto [operandNo, operand] : llvm::enumerate(yieldOperands)) {
515 auto *defOp = operand.getDefiningOp();
516 if (defOp && defOp->hasTrait<OpTrait::ConstantLike>()) {
517 // If the constant is available outside the process, use it directly;
518 // otherwise move it outside.
519 if (!defOp->getParentRegion()->isProperAncestor(&op.getBody())) {
520 defOp->moveBefore(op);
521 }
522 rewriter.replaceAllUsesWith(op.getResult(operandNo), operand);
523 operandsToErase.set(operandNo);
524 continue;
525 }
526
527 // Identify duplicate operands to merge and compute updated result
528 // positions for the process operation.
529 if (!uniqueOperands.contains(operand)) {
530 const auto newPos = uniqueOperands.size();
531 uniqueOperands.insert(std::make_pair(operand, newPos));
532 origToNewPos.insert(std::make_pair(operandNo, newPos));
533 } else {
534 auto firstOccurrencePos = uniqueOperands.lookup(operand);
535 origToNewPos.insert(std::make_pair(operandNo, firstOccurrencePos));
536 operandsToErase.set(operandNo);
537 }
538 }
539
540 const auto countOperandsToErase = operandsToErase.count();
541 if (countOperandsToErase == 0)
542 return failure();
543
544 // Remove the process operation if all its results have been replaced with
545 // constants.
546 if (countOperandsToErase == op.getNumResults()) {
547 rewriter.eraseOp(op);
548 return success();
549 }
550
551 haltOp->eraseOperands(operandsToErase);
552
553 SmallVector<Type> resultTypes = llvm::to_vector(haltOp->getOperandTypes());
554 auto newProcessOp = ProcessOp::create(rewriter, op.getLoc(), resultTypes,
555 op->getOperands(), op->getAttrs());
556 newProcessOp.getBody().takeBody(op.getBody());
557
558 // Update old results with new values, accounting for pruned halt operands.
559 for (auto oldResult : op.getResults()) {
560 auto newResultPos = origToNewPos.find(oldResult.getResultNumber());
561 if (newResultPos == origToNewPos.end())
562 continue;
563 auto newResult = newProcessOp.getResult(newResultPos->getSecond());
564 rewriter.replaceAllUsesWith(oldResult, newResult);
565 }
566
567 rewriter.eraseOp(op);
568 return success();
569}
570
571//===----------------------------------------------------------------------===//
572// CombinationalOp
573//===----------------------------------------------------------------------===//
574
575LogicalResult CombinationalOp::canonicalize(CombinationalOp op,
576 PatternRewriter &rewriter) {
577 // Inline the combinational region if it consists of a single block and
578 // contains no side-effecting operations.
579 if (op.getBody().hasOneBlock() && isMemoryEffectFree(op)) {
580 auto &block = op.getBody().front();
581 auto *terminator = block.getTerminator();
582 rewriter.inlineBlockBefore(&block, op, ValueRange{});
583 rewriter.replaceOp(op, terminator->getOperands());
584 rewriter.eraseOp(terminator);
585 return success();
586 }
587 return failure();
588}
589
590//===----------------------------------------------------------------------===//
591// WaitOp
592//===----------------------------------------------------------------------===//
593
594static LogicalResult verifyYieldResults(Operation *op,
595 ValueRange yieldOperands) {
596 // Determine the result values of the parent.
597 auto *parentOp = op->getParentOp();
598 TypeRange resultTypes = TypeSwitch<Operation *, TypeRange>(parentOp)
599 .Case<ProcessOp, CombinationalOp>(
600 [](auto op) { return op.getResultTypes(); })
601 .Case<FinalOp>([](auto) { return TypeRange{}; });
602
603 // Check that the number of yield operands matches the process.
604 if (yieldOperands.size() != resultTypes.size())
605 return op->emitOpError()
606 << "has " << yieldOperands.size()
607 << " yield operands, but enclosing '" << parentOp->getName()
608 << "' returns " << resultTypes.size();
609
610 // Check that the types match.
611 for (unsigned i = 0; i < yieldOperands.size(); ++i)
612 if (yieldOperands[i].getType() != resultTypes[i])
613 return op->emitError()
614 << "type of yield operand " << i << " ("
615 << yieldOperands[i].getType() << ") does not match enclosing '"
616 << parentOp->getName() << "' result type (" << resultTypes[i]
617 << ")";
618
619 return success();
620}
621
622LogicalResult WaitOp::verify() {
623 return verifyYieldResults(*this, getYieldOperands());
624}
625
626//===----------------------------------------------------------------------===//
627// HaltOp
628//===----------------------------------------------------------------------===//
629
630LogicalResult HaltOp::verify() {
631 return verifyYieldResults(*this, getYieldOperands());
632}
633
634//===----------------------------------------------------------------------===//
635// YieldOp
636//===----------------------------------------------------------------------===//
637
638LogicalResult YieldOp::verify() {
639 return verifyYieldResults(*this, getYieldOperands());
640}
641
642//===----------------------------------------------------------------------===//
643// Auto-Generated Implementations
644//===----------------------------------------------------------------------===//
645
646#define GET_OP_CLASSES
647#include "circt/Dialect/LLHD/IR/LLHD.cpp.inc"
648#include "circt/Dialect/LLHD/IR/LLHDEnums.cpp.inc"
assert(baseType &&"element must be base type")
static Value getValueAtIndex(OpBuilder &builder, Location loc, Value val, unsigned index)
Definition LLHDOps.cpp:69
static void getSortedPtrs(DenseMap< Attribute, MemorySlot > &subslots, SmallVectorImpl< std::pair< unsigned, Value > > &sorted)
Definition LLHDOps.cpp:367
static LogicalResult verifyYieldResults(Operation *op, ValueRange yieldOperands)
Definition LLHDOps.cpp:594
static OpFoldResult foldSigPtrArraySliceOp(Op op, ArrayRef< Attribute > operands)
Definition LLHDOps.cpp:175
static LogicalResult canonicalizeSigPtrArraySliceOp(Op op, PatternRewriter &rewriter)
Definition LLHDOps.cpp:197
static OpFoldResult foldSigPtrExtractOp(Op op, ArrayRef< Attribute > operands)
Definition LLHDOps.cpp:149
static LogicalResult inferReturnTypesOfStructExtractOp(MLIRContext *context, std::optional< Location > loc, ValueRange operands, DictionaryAttr attrs, mlir::OpaqueProperties properties, mlir::RegionRange regions, SmallVectorImpl< Type > &results)
Definition LLHDOps.cpp:283
static Location getLoc(DefSlot slot)
Definition Mem2Reg.cpp:216
static InstancePath empty
create(elements)
Definition hw.py:483
create(array_value, idx)
Definition hw.py:450
create(data_type, value)
Definition hw.py:433
create(elements, Type result_type=None)
Definition hw.py:532
create(struct_value, str field_name)
Definition hw.py:556
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)
Definition LLHDOps.cpp:26
Type getLLHDElementType(Type type)
Definition LLHDOps.cpp:38
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
Definition LLVM.h:183