CIRCT 23.0.0git
Loading...
Searching...
No Matches
CombOps.cpp
Go to the documentation of this file.
1//===- CombOps.cpp - Implement the Comb operations ------------------------===//
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//
9// This file implements combinational ops.
10//
11//===----------------------------------------------------------------------===//
12
16#include "mlir/IR/Builders.h"
17#include "mlir/IR/ImplicitLocOpBuilder.h"
18#include "mlir/IR/Matchers.h"
19#include "mlir/IR/PatternMatch.h"
20#include "llvm/Support/FormatVariadic.h"
21#include <limits>
22
23using namespace circt;
24using namespace comb;
25
26Value comb::createZExt(OpBuilder &builder, Location loc, Value value,
27 unsigned targetWidth) {
28 assert(value.getType().isSignlessInteger());
29 auto inputWidth = value.getType().getIntOrFloatBitWidth();
30 assert(inputWidth <= targetWidth);
31
32 // Nothing to do if the width already matches.
33 if (inputWidth == targetWidth)
34 return value;
35
36 // Create a zero constant for the upper bits.
37 auto zeros = hw::ConstantOp::create(
38 builder, loc, builder.getIntegerType(targetWidth - inputWidth), 0);
39 return builder.createOrFold<ConcatOp>(loc, zeros, value);
40}
41
42/// Create a sign extension operation from a value of integer type to an equal
43/// or larger integer type.
44Value comb::createOrFoldSExt(OpBuilder &builder, Location loc, Value value,
45 Type destTy) {
46 IntegerType valueType = dyn_cast<IntegerType>(value.getType());
47 assert(valueType && isa<IntegerType>(destTy) &&
48 valueType.getWidth() <= destTy.getIntOrFloatBitWidth() &&
49 valueType.getWidth() != 0 && "invalid sext operands");
50 // If already the right size, we are done.
51 if (valueType == destTy)
52 return value;
53
54 // sext is concat with a replicate of the sign bits and the bottom part.
55 auto signBit =
56 builder.createOrFold<ExtractOp>(loc, value, valueType.getWidth() - 1, 1);
57 auto signBits = builder.createOrFold<ReplicateOp>(
58 loc, signBit, destTy.getIntOrFloatBitWidth() - valueType.getWidth());
59 return builder.createOrFold<ConcatOp>(loc, signBits, value);
60}
61
62Value comb::createOrFoldSExt(ImplicitLocOpBuilder &builder, Value value,
63 Type destTy) {
64 return createOrFoldSExt(builder, builder.getLoc(), value, destTy);
65}
66
67Value comb::createOrFoldNot(OpBuilder &builder, Location loc, Value value,
68 bool twoState) {
69 auto allOnes = hw::ConstantOp::create(builder, loc, value.getType(), -1);
70 return builder.createOrFold<XorOp>(loc, value, allOnes, twoState);
71}
72
73Value comb::createOrFoldNot(ImplicitLocOpBuilder &builder, Value value,
74 bool twoState) {
75 return createOrFoldNot(builder, builder.getLoc(), value, twoState);
76}
77
78// Extract individual bits from a value
79void comb::extractBits(OpBuilder &builder, Value val,
80 SmallVectorImpl<Value> &bits) {
81 assert(val.getType().isInteger() && "expected integer");
82 auto width = val.getType().getIntOrFloatBitWidth();
83 bits.reserve(width);
84
85 // Check if we can reuse concat operands
86 if (auto concat = val.getDefiningOp<comb::ConcatOp>()) {
87 if (concat.getNumOperands() == width &&
88 llvm::all_of(concat.getOperandTypes(), [](Type type) {
89 return type.getIntOrFloatBitWidth() == 1;
90 })) {
91 // Reverse the operands to match the bit order
92 bits.append(std::make_reverse_iterator(concat.getOperands().end()),
93 std::make_reverse_iterator(concat.getOperands().begin()));
94 return;
95 }
96 }
97
98 // Extract individual bits
99 for (int64_t i = 0; i < width; ++i)
100 bits.push_back(
101 builder.createOrFold<comb::ExtractOp>(val.getLoc(), val, i, 1));
102}
103
104// Construct a mux tree for given leaf nodes. `selectors` is the selector for
105// each level of the tree. Currently the selector is tested from MSB to LSB.
106Value comb::constructMuxTree(OpBuilder &builder, Location loc,
107 ArrayRef<Value> selectors,
108 ArrayRef<Value> leafNodes,
109 Value outOfBoundsValue) {
110 // Recursive helper function to construct the mux tree
111 std::function<Value(size_t, size_t)> constructTreeHelper =
112 [&](size_t id, size_t level) -> Value {
113 // Base case: at the lowest level, return the result
114 if (level == 0) {
115 // Return the result for the given index. If the index is out of bounds,
116 // return the out-of-bound value.
117 return id < leafNodes.size() ? leafNodes[id] : outOfBoundsValue;
118 }
119
120 auto selector = selectors[level - 1];
121
122 // Recursive case: create muxes for true and false branches
123 auto trueVal = constructTreeHelper(2 * id + 1, level - 1);
124 auto falseVal = constructTreeHelper(2 * id, level - 1);
125
126 // Combine the results with a mux
127 return builder.createOrFold<comb::MuxOp>(loc, selector, trueVal, falseVal);
128 };
129
130 return constructTreeHelper(0, llvm::Log2_64_Ceil(leafNodes.size()));
131}
132
133Value comb::createDynamicExtract(OpBuilder &builder, Location loc, Value value,
134 Value offset, unsigned width) {
135 assert(value.getType().isSignlessInteger());
136 auto valueWidth = value.getType().getIntOrFloatBitWidth();
137 assert(width <= valueWidth);
138
139 // Handle the special case where the offset is constant.
140 APInt constOffset;
141 if (matchPattern(offset, mlir::m_ConstantInt(&constOffset)))
142 if (constOffset.getActiveBits() < 32)
143 return builder.createOrFold<comb::ExtractOp>(
144 loc, value, constOffset.getZExtValue(), width);
145
146 // Zero-extend the offset, shift the value down, and extract the requested
147 // number of bits.
148 offset = createZExt(builder, loc, offset, valueWidth);
149 value = builder.createOrFold<comb::ShrUOp>(loc, value, offset);
150 return builder.createOrFold<comb::ExtractOp>(loc, value, 0, width);
151}
152
153Value comb::createDynamicInject(OpBuilder &builder, Location loc, Value value,
154 Value offset, Value replacement,
155 bool twoState) {
156 assert(value.getType().isSignlessInteger());
157 assert(replacement.getType().isSignlessInteger());
158 auto largeWidth = value.getType().getIntOrFloatBitWidth();
159 auto smallWidth = replacement.getType().getIntOrFloatBitWidth();
160 assert(smallWidth <= largeWidth);
161
162 // If we're inserting a zero-width value there's nothing to do.
163 if (smallWidth == 0)
164 return value;
165
166 // Handle the special case where the offset is constant.
167 APInt constOffset;
168 if (matchPattern(offset, mlir::m_ConstantInt(&constOffset)))
169 if (constOffset.getActiveBits() < 32)
170 return createInject(builder, loc, value, constOffset.getZExtValue(),
171 replacement);
172
173 // Zero-extend the offset and clear the value bits we are replacing.
174 offset = createZExt(builder, loc, offset, largeWidth);
175 Value mask = hw::ConstantOp::create(
176 builder, loc, APInt::getLowBitsSet(largeWidth, smallWidth));
177 mask = builder.createOrFold<comb::ShlOp>(loc, mask, offset);
178 mask = createOrFoldNot(builder, loc, mask, true);
179 value = builder.createOrFold<comb::AndOp>(loc, value, mask, twoState);
180
181 // Zero-extend the replacement value, shift it up to the offset, and merge it
182 // with the value that has the corresponding bits cleared.
183 replacement = createZExt(builder, loc, replacement, largeWidth);
184 replacement = builder.createOrFold<comb::ShlOp>(loc, replacement, offset);
185 return builder.createOrFold<comb::OrOp>(loc, value, replacement, twoState);
186}
187
188Value comb::createInject(OpBuilder &builder, Location loc, Value value,
189 unsigned offset, Value replacement) {
190 assert(value.getType().isSignlessInteger());
191 assert(replacement.getType().isSignlessInteger());
192 auto largeWidth = value.getType().getIntOrFloatBitWidth();
193 auto smallWidth = replacement.getType().getIntOrFloatBitWidth();
194 assert(smallWidth <= largeWidth);
195
196 // If the offset is outside the value there's nothing to do.
197 if (offset >= largeWidth)
198 return value;
199
200 // If we're inserting a zero-width value there's nothing to do.
201 if (smallWidth == 0)
202 return value;
203
204 // Assemble the pieces of the injection as everything below the offset, the
205 // replacement value, and everything above the replacement value.
206 SmallVector<Value, 3> fragments;
207 auto end = offset + smallWidth;
208 if (end < largeWidth)
209 fragments.push_back(
210 comb::ExtractOp::create(builder, loc, value, end, largeWidth - end));
211 if (end <= largeWidth)
212 fragments.push_back(replacement);
213 else
214 fragments.push_back(comb::ExtractOp::create(builder, loc, replacement, 0,
215 largeWidth - offset));
216 if (offset > 0)
217 fragments.push_back(
218 comb::ExtractOp::create(builder, loc, value, 0, offset));
219 return builder.createOrFold<comb::ConcatOp>(loc, fragments);
220}
221
222llvm::LogicalResult comb::convertSubToAdd(comb::SubOp subOp,
223 mlir::PatternRewriter &rewriter) {
224 auto lhs = subOp.getLhs();
225 auto rhs = subOp.getRhs();
226 // Since `-rhs = ~rhs + 1` holds, rewrite `sub(lhs, rhs)` to:
227 // sub(lhs, rhs) => add(lhs, -rhs) => add(lhs, add(~rhs, 1))
228 // => add(lhs, ~rhs, 1)
229 auto notRhs =
230 comb::createOrFoldNot(rewriter, subOp.getLoc(), rhs, subOp.getTwoState());
231 auto one =
232 hw::ConstantOp::create(rewriter, subOp.getLoc(), subOp.getType(), 1);
233 replaceOpWithNewOpAndCopyNamehint<comb::AddOp>(
234 rewriter, subOp, ValueRange{lhs, notRhs, one}, subOp.getTwoState());
235 return success();
236}
237
238static llvm::LogicalResult convertDivModUByPowerOfTwo(PatternRewriter &rewriter,
239 Operation *op, Value lhs,
240 Value rhs, bool isDiv) {
241 // Check if the divisor is a power of two constant.
242 auto rhsConstantOp = rhs.getDefiningOp<hw::ConstantOp>();
243 if (!rhsConstantOp)
244 return failure();
245
246 APInt rhsValue = rhsConstantOp.getValue();
247 if (!rhsValue.isPowerOf2())
248 return failure();
249
250 Location loc = op->getLoc();
251
252 unsigned width = lhs.getType().getIntOrFloatBitWidth();
253 unsigned bitPosition = rhsValue.ceilLogBase2();
254
255 if (isDiv) {
256 // divu(x, 2^n) -> concat(0...0, extract(x, n, width-n))
257 // This is equivalent to a right shift by n bits.
258
259 // Extract the upper bits (equivalent to right shift).
260 Value upperBits = rewriter.createOrFold<comb::ExtractOp>(
261 loc, lhs, bitPosition, width - bitPosition);
262
263 // Concatenate with zeros on the left.
264 Value zeros =
265 hw::ConstantOp::create(rewriter, loc, APInt::getZero(bitPosition));
266
267 // use replaceOpWithNewOpAndCopyNamehint?
269 rewriter, op,
270 comb::ConcatOp::create(rewriter, loc,
271 ArrayRef<Value>{zeros, upperBits}));
272 return success();
273 }
274
275 // modu(x, 2^n) -> concat(0...0, extract(x, 0, n))
276 // This extracts the lower n bits (equivalent to bitwise AND with 2^n - 1).
277
278 // Extract the lower bits.
279 Value lowerBits =
280 rewriter.createOrFold<comb::ExtractOp>(loc, lhs, 0, bitPosition);
281
282 // Concatenate with zeros on the left.
283 Value zeros = hw::ConstantOp::create(rewriter, loc,
284 APInt::getZero(width - bitPosition));
285
287 rewriter, op,
288 comb::ConcatOp::create(rewriter, loc, ArrayRef<Value>{zeros, lowerBits}));
289 return success();
290}
291
292LogicalResult comb::convertDivUByPowerOfTwo(DivUOp divOp,
293 mlir::PatternRewriter &rewriter) {
294 return convertDivModUByPowerOfTwo(rewriter, divOp, divOp.getLhs(),
295 divOp.getRhs(), /*isDiv=*/true);
296}
297
298LogicalResult comb::convertModUByPowerOfTwo(ModUOp modOp,
299 mlir::PatternRewriter &rewriter) {
300 return convertDivModUByPowerOfTwo(rewriter, modOp, modOp.getLhs(),
301 modOp.getRhs(), /*isDiv=*/false);
302}
303
304//===----------------------------------------------------------------------===//
305// ICmpOp
306//===----------------------------------------------------------------------===//
307
308ICmpPredicate ICmpOp::getFlippedPredicate(ICmpPredicate predicate) {
309 switch (predicate) {
310 case ICmpPredicate::eq:
311 return ICmpPredicate::eq;
312 case ICmpPredicate::ne:
313 return ICmpPredicate::ne;
314 case ICmpPredicate::slt:
315 return ICmpPredicate::sgt;
316 case ICmpPredicate::sle:
317 return ICmpPredicate::sge;
318 case ICmpPredicate::sgt:
319 return ICmpPredicate::slt;
320 case ICmpPredicate::sge:
321 return ICmpPredicate::sle;
322 case ICmpPredicate::ult:
323 return ICmpPredicate::ugt;
324 case ICmpPredicate::ule:
325 return ICmpPredicate::uge;
326 case ICmpPredicate::ugt:
327 return ICmpPredicate::ult;
328 case ICmpPredicate::uge:
329 return ICmpPredicate::ule;
330 case ICmpPredicate::ceq:
331 return ICmpPredicate::ceq;
332 case ICmpPredicate::cne:
333 return ICmpPredicate::cne;
334 case ICmpPredicate::weq:
335 return ICmpPredicate::weq;
336 case ICmpPredicate::wne:
337 return ICmpPredicate::wne;
338 }
339 llvm_unreachable("unknown comparison predicate");
340}
341
342bool ICmpOp::isPredicateSigned(ICmpPredicate predicate) {
343 switch (predicate) {
344 case ICmpPredicate::ult:
345 case ICmpPredicate::ugt:
346 case ICmpPredicate::ule:
347 case ICmpPredicate::uge:
348 case ICmpPredicate::ne:
349 case ICmpPredicate::eq:
350 case ICmpPredicate::cne:
351 case ICmpPredicate::ceq:
352 case ICmpPredicate::wne:
353 case ICmpPredicate::weq:
354 return false;
355 case ICmpPredicate::slt:
356 case ICmpPredicate::sgt:
357 case ICmpPredicate::sle:
358 case ICmpPredicate::sge:
359 return true;
360 }
361 llvm_unreachable("unknown comparison predicate");
362}
363
364/// Returns the predicate for a logically negated comparison, e.g. mapping
365/// EQ => NE and SLE => SGT.
366ICmpPredicate ICmpOp::getNegatedPredicate(ICmpPredicate predicate) {
367 switch (predicate) {
368 case ICmpPredicate::eq:
369 return ICmpPredicate::ne;
370 case ICmpPredicate::ne:
371 return ICmpPredicate::eq;
372 case ICmpPredicate::slt:
373 return ICmpPredicate::sge;
374 case ICmpPredicate::sle:
375 return ICmpPredicate::sgt;
376 case ICmpPredicate::sgt:
377 return ICmpPredicate::sle;
378 case ICmpPredicate::sge:
379 return ICmpPredicate::slt;
380 case ICmpPredicate::ult:
381 return ICmpPredicate::uge;
382 case ICmpPredicate::ule:
383 return ICmpPredicate::ugt;
384 case ICmpPredicate::ugt:
385 return ICmpPredicate::ule;
386 case ICmpPredicate::uge:
387 return ICmpPredicate::ult;
388 case ICmpPredicate::ceq:
389 return ICmpPredicate::cne;
390 case ICmpPredicate::cne:
391 return ICmpPredicate::ceq;
392 case ICmpPredicate::weq:
393 return ICmpPredicate::wne;
394 case ICmpPredicate::wne:
395 return ICmpPredicate::weq;
396 }
397 llvm_unreachable("unknown comparison predicate");
398}
399
400/// Return true if this is an equality test with -1, which is a "reduction
401/// and" operation in Verilog.
402bool ICmpOp::isEqualAllOnes() {
403 if (getPredicate() != ICmpPredicate::eq)
404 return false;
405
406 if (auto op1 =
407 dyn_cast_or_null<hw::ConstantOp>(getOperand(1).getDefiningOp()))
408 return op1.getValue().isAllOnes();
409 return false;
410}
411
412/// Return true if this is a not equal test with 0, which is a "reduction
413/// or" operation in Verilog.
414bool ICmpOp::isNotEqualZero() {
415 if (getPredicate() != ICmpPredicate::ne)
416 return false;
417
418 if (auto op1 =
419 dyn_cast_or_null<hw::ConstantOp>(getOperand(1).getDefiningOp()))
420 return op1.getValue().isZero();
421 return false;
422}
423
424//===----------------------------------------------------------------------===//
425// Unary Operations
426//===----------------------------------------------------------------------===//
427
428LogicalResult ReplicateOp::verify() {
429 // The source must be equal or smaller than the dest type, and an even
430 // multiple of it. Both are already known to be signless integers.
431 auto srcWidth = cast<IntegerType>(getOperand().getType()).getWidth();
432 auto dstWidth = cast<IntegerType>(getType()).getWidth();
433
434 if (srcWidth > dstWidth)
435 return emitOpError("replicate cannot shrink bitwidth of operand"),
436 failure();
437
438 if ((srcWidth == 0 && dstWidth != 0) ||
439 (srcWidth != 0 && dstWidth % srcWidth))
440 return emitOpError("replicate must produce integer multiple of operand"),
441 failure();
442
443 return success();
444}
445
446//===----------------------------------------------------------------------===//
447// Variadic operations
448//===----------------------------------------------------------------------===//
449
450static LogicalResult verifyUTBinOp(Operation *op) {
451 if (op->getOperands().empty())
452 return op->emitOpError("requires 1 or more args");
453 return success();
454}
455
456LogicalResult AddOp::verify() { return verifyUTBinOp(*this); }
457
458LogicalResult MulOp::verify() { return verifyUTBinOp(*this); }
459
460LogicalResult AndOp::verify() { return verifyUTBinOp(*this); }
461
462LogicalResult OrOp::verify() { return verifyUTBinOp(*this); }
463
464LogicalResult XorOp::verify() { return verifyUTBinOp(*this); }
465
466/// Return true if this is a two operand xor with an all ones constant as
467/// its RHS operand.
468bool XorOp::isBinaryNot() {
469 if (getNumOperands() != 2)
470 return false;
471 if (auto cst = getOperand(1).getDefiningOp<hw::ConstantOp>())
472 if (cst.getValue().isAllOnes())
473 return true;
474 return false;
475}
476
477//===----------------------------------------------------------------------===//
478// ConcatOp
479//===----------------------------------------------------------------------===//
480
481static unsigned getTotalWidth(ValueRange inputs) {
482 unsigned resultWidth = 0;
483 for (auto input : inputs) {
484 resultWidth += hw::type_cast<IntegerType>(input.getType()).getWidth();
485 }
486 return resultWidth;
487}
488
489void ConcatOp::build(OpBuilder &builder, OperationState &result, Value hd,
490 ValueRange tl) {
491 result.addOperands(ValueRange{hd});
492 result.addOperands(tl);
493 unsigned hdWidth = cast<IntegerType>(hd.getType()).getWidth();
494 result.addTypes(builder.getIntegerType(getTotalWidth(tl) + hdWidth));
495}
496
497LogicalResult ConcatOp::inferReturnTypes(
498 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
499 DictionaryAttr attrs, mlir::OpaqueProperties properties,
500 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
501 unsigned resultWidth = getTotalWidth(operands);
502 results.push_back(IntegerType::get(context, resultWidth));
503 return success();
504}
505
506/// Parse a ConcatOp that can either follow the format:
507/// $inputs attr-dict `:` qualified(type($inputs))
508/// or have no operands, colon and typelist.
509ParseResult ConcatOp::parse(OpAsmParser &parser, OperationState &result) {
510 SmallVector<OpAsmParser::UnresolvedOperand, 4> operands;
511 SmallVector<Type, 4> types;
512
513 llvm::SMLoc allOperandLoc = parser.getCurrentLocation();
514
515 // Parse the operand list, attributes and colon
516 if (parser.parseOperandList(operands) ||
517 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon())
518 return failure();
519
520 // Parse an optional list of types
521 Type parsedType;
522 auto parseResult = parser.parseOptionalType(parsedType);
523 if (parseResult.has_value()) {
524 if (failed(parseResult.value()))
525 return failure();
526 types.push_back(parsedType);
527 while (succeeded(parser.parseOptionalComma())) {
528 if (parser.parseType(parsedType))
529 return failure();
530 types.push_back(parsedType);
531 }
532 }
533
534 if (parser.resolveOperands(operands, types, allOperandLoc, result.operands))
535 return failure();
536
537 SmallVector<Type, 1> inferredTypes;
538 if (failed(ConcatOp::inferReturnTypes(
539 parser.getContext(), result.location, result.operands,
540 result.attributes.getDictionary(parser.getContext()),
541 result.getRawProperties(), {}, inferredTypes)))
542 return failure();
543
544 result.addTypes(inferredTypes);
545 return success();
546}
547
548void ConcatOp::print(OpAsmPrinter &p) {
549 p << " ";
550 p.printOperands(getOperands());
551 p.printOptionalAttrDict((*this)->getAttrs());
552 p << " : ";
553 llvm::interleaveComma(getOperandTypes(), p);
554}
555
556//===----------------------------------------------------------------------===//
557// ReverseOp
558//===----------------------------------------------------------------------===//
559
560// Folding of ReverseOp: if the input is constant, compute the reverse at
561// compile time.
562OpFoldResult comb::ReverseOp::fold(FoldAdaptor adaptor) {
563 // Try to cast the input attribute to an IntegerAttr.
564 auto cstInput = llvm::dyn_cast_or_null<mlir::IntegerAttr>(adaptor.getInput());
565 if (!cstInput)
566 return {};
567
568 APInt val = cstInput.getValue();
569 APInt reversedVal = val.reverseBits();
570
571 return mlir::IntegerAttr::get(getType(), reversedVal);
572}
573
574namespace {
575struct ReverseOfReverse : public OpRewritePattern<comb::ReverseOp> {
576 using OpRewritePattern<comb::ReverseOp>::OpRewritePattern;
577
578 LogicalResult matchAndRewrite(comb::ReverseOp op,
579 PatternRewriter &rewriter) const override {
580 auto inputOp = op.getInput().getDefiningOp<comb::ReverseOp>();
581 if (!inputOp)
582 return failure();
583
584 rewriter.replaceOp(op, inputOp.getInput());
585 return success();
586 }
587};
588} // namespace
589
590void comb::ReverseOp::getCanonicalizationPatterns(RewritePatternSet &results,
591 MLIRContext *context) {
592 results.add<ReverseOfReverse>(context);
593}
594
595//===----------------------------------------------------------------------===//
596// Other Operations
597//===----------------------------------------------------------------------===//
598
599LogicalResult ExtractOp::verify() {
600 unsigned srcWidth = cast<IntegerType>(getInput().getType()).getWidth();
601 unsigned dstWidth = cast<IntegerType>(getType()).getWidth();
602
603 bool checkAddWillOverflow =
604 getLowBit() > std::numeric_limits<decltype(dstWidth)>::max() - dstWidth;
605
606 // Checks that all extracted bits from the source are well-defined.
607 // While it is well-defined to extract i0 outside of the bounds of another
608 // integer (because i0 contains no bits and they are therefore all
609 // well-defined), the verifier will refuse it except for right after the input
610 // value, as it is otherwise likely a bug in user code. This constraint can be
611 // lifted and tested for if it proves useful to do so.
612 if (checkAddWillOverflow || getLowBit() + dstWidth > srcWidth)
613 return emitOpError("from bit too large for input"), failure();
614
615 return success();
616}
617
618LogicalResult TruthTableOp::verify() {
619 size_t numInputs = getInputs().size();
620 if (numInputs >= sizeof(size_t) * 8)
621 return emitOpError("Truth tables support a maximum of ")
622 << sizeof(size_t) * 8 - 1 << " inputs on your platform";
623
624 auto table = getLookupTable();
625 if (table.size() != (1ull << numInputs))
626 return emitOpError("Expected lookup table of 2^n length");
627 return success();
628}
629
630//===----------------------------------------------------------------------===//
631// TableGen generated logic.
632//===----------------------------------------------------------------------===//
633
634// Provide the autogenerated implementation guts for the Op classes.
635#define GET_OP_CLASSES
636#include "circt/Dialect/Comb/Comb.cpp.inc"
assert(baseType &&"element must be base type")
static size_t getTotalWidth(ArrayRef< Value > operands)
static LogicalResult verifyUTBinOp(Operation *op)
Definition CombOps.cpp:450
static llvm::LogicalResult convertDivModUByPowerOfTwo(PatternRewriter &rewriter, Operation *op, Value lhs, Value rhs, bool isDiv)
Definition CombOps.cpp:238
static std::unique_ptr< Context > context
create(low_bit, result_type, input=None)
Definition comb.py:187
create(data_type, value)
Definition hw.py:433
Value createOrFoldNot(OpBuilder &builder, Location loc, Value value, bool twoState=false)
Create a `‘Not’' gate on a value.
Definition CombOps.cpp:67
Value createInject(OpBuilder &builder, Location loc, Value value, unsigned offset, Value replacement)
Replace a range of bits in an integer and return the updated integer value.
Definition CombOps.cpp:188
Value createZExt(OpBuilder &builder, Location loc, Value value, unsigned targetWidth)
Create the ops to zero-extend a value to an integer of equal or larger type.
Definition CombOps.cpp:26
Value createOrFoldSExt(OpBuilder &builder, Location loc, Value value, Type destTy)
Create a sign extension operation from a value of integer type to an equal or larger integer type.
Definition CombOps.cpp:44
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void replaceOpAndCopyNamehint(PatternRewriter &rewriter, Operation *op, Value newValue)
A wrapper of PatternRewriter::replaceOp to propagate "sv.namehint" attribute.
Definition Naming.cpp:73
Definition comb.py:1