CIRCT 20.0.0git
Loading...
Searching...
No Matches
AIGOps.cpp
Go to the documentation of this file.
1//===- AIGOps.cpp - AIG Dialect Operations ----------------------*- C++ -*-===//
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 implement the AIG ops.
10//
11//===----------------------------------------------------------------------===//
12
15#include "mlir/IR/PatternMatch.h"
16
17using namespace mlir;
18using namespace circt;
19using namespace circt::aig;
20
21#define GET_OP_CLASSES
22#include "circt/Dialect/AIG/AIG.cpp.inc"
23
24OpFoldResult AndInverterOp::fold(FoldAdaptor adaptor) {
25 if (getNumOperands() == 1 && !isInverted(0))
26 return getOperand(0);
27 return {};
28}
29
30LogicalResult AndInverterOp::canonicalize(AndInverterOp op,
31 PatternRewriter &rewriter) {
33 SmallVector<Value> uniqueValues;
34 SmallVector<bool> uniqueInverts;
35
36 APInt constValue =
37 APInt::getAllOnes(op.getResult().getType().getIntOrFloatBitWidth());
38
39 bool invertedConstFound = false;
40
41 for (auto [value, inverted] : llvm::zip(op.getInputs(), op.getInverted())) {
42 if (auto constOp = value.getDefiningOp<hw::ConstantOp>()) {
43 if (inverted) {
44 constValue &= ~constOp.getValue();
45 invertedConstFound = true;
46 } else {
47 constValue &= constOp.getValue();
48 }
49 continue;
50 }
51
52 auto it = seen.find(value);
53 if (it == seen.end()) {
54 seen.insert({value, inverted});
55 uniqueValues.push_back(value);
56 uniqueInverts.push_back(inverted);
57 } else if (it->second != inverted) {
58 // replace with const 0
59 rewriter.replaceOpWithNewOp<hw::ConstantOp>(
60 op, APInt::getZero(value.getType().getIntOrFloatBitWidth()));
61 return success();
62 }
63 }
64
65 // If the constant is zero, we can just replace with zero.
66 if (constValue.isZero()) {
67 rewriter.replaceOpWithNewOp<hw::ConstantOp>(op, constValue);
68 return success();
69 }
70
71 // No change.
72 if (uniqueValues.size() == op.getInputs().size() ||
73 (!constValue.isAllOnes() && !invertedConstFound &&
74 uniqueValues.size() + 1 == op.getInputs().size()))
75 return failure();
76
77 if (!constValue.isAllOnes()) {
78 auto constOp = rewriter.create<hw::ConstantOp>(op.getLoc(), constValue);
79 uniqueInverts.push_back(false);
80 uniqueValues.push_back(constOp);
81 }
82
83 // It means the input is reduced to all ones.
84 if (uniqueValues.empty()) {
85 rewriter.replaceOpWithNewOp<hw::ConstantOp>(op, constValue);
86 return success();
87 }
88
89 // build new op with reduced input values
90 rewriter.replaceOpWithNewOp<aig::AndInverterOp>(op, uniqueValues,
91 uniqueInverts);
92 return success();
93}
94
95ParseResult AndInverterOp::parse(OpAsmParser &parser, OperationState &result) {
96 SmallVector<OpAsmParser::UnresolvedOperand> operands;
97 SmallVector<bool> inverts;
98 auto loc = parser.getCurrentLocation();
99
100 while (true) {
101 inverts.push_back(succeeded(parser.parseOptionalKeyword("not")));
102 operands.push_back(OpAsmParser::UnresolvedOperand());
103
104 if (parser.parseOperand(operands.back()))
105 return failure();
106 if (parser.parseOptionalComma())
107 break;
108 }
109
110 Type type;
111 if (parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
112 parser.parseCustomTypeWithFallback(type))
113 return failure();
114
115 result.addTypes({type});
116 result.addAttribute("inverted",
117 parser.getBuilder().getDenseBoolArrayAttr(inverts));
118 if (parser.resolveOperands(operands, type, loc, result.operands))
119 return failure();
120 return success();
121}
122
123void AndInverterOp::print(OpAsmPrinter &odsPrinter) {
124 odsPrinter << ' ';
125 llvm::interleaveComma(llvm::zip(getInverted(), getInputs()), odsPrinter,
126 [&](auto &&pair) {
127 auto [invert, input] = pair;
128 if (invert) {
129 odsPrinter << "not ";
130 }
131 odsPrinter << input;
132 });
133 odsPrinter.printOptionalAttrDict((*this)->getAttrs(), {"inverted"});
134 odsPrinter << " : " << getResult().getType();
135}
136
137APInt AndInverterOp::evaluate(ArrayRef<APInt> inputs) {
138 assert(inputs.size() == getNumOperands() &&
139 "Expected as many inputs as operands");
140 assert(!inputs.empty() && "Expected non-empty input list");
141 APInt result = APInt::getAllOnes(inputs.front().getBitWidth());
142 for (auto [idx, input] : llvm::enumerate(inputs)) {
143 if (isInverted(idx))
144 result &= ~input;
145 else
146 result &= input;
147 }
148 return result;
149}
150
151LogicalResult CutOp::verify() {
152 auto *block = getBody();
153 // NOTE: Currently input and output types of the block must be exactly the
154 // same. We might want to relax this in the future as a way to represent
155 // "vectorized" cuts. For example in the following cut, the block arguments
156 // types are i1, but the cut is batch-applied over 8-bit lanes.
157 // %0 = aig.cut %a, %b : (i8, i8) -> (i8) {
158 // ^bb0(%arg0: i1, %arg1: i1):
159 // %c = aig.and_inv %arg0, not %arg1 : i1
160 // aig.output %c : i1
161 // }
162
163 if (getInputs().size() != block->getNumArguments())
164 return emitOpError("the number of inputs and the number of block arguments "
165 "do not match. Expected ")
166 << getInputs().size() << " but got " << block->getNumArguments();
167
168 // Check input types.
169 for (auto [input, arg] : llvm::zip(getInputs(), block->getArguments()))
170 if (input.getType() != arg.getType())
171 return emitOpError("input type ")
172 << input.getType() << " does not match "
173 << "block argument type " << arg.getType();
174
175 if (getNumResults() != block->getTerminator()->getNumOperands())
176 return emitOpError("the number of results and the number of terminator "
177 "operands do not match. Expected ")
178 << getNumResults() << " but got "
179 << block->getTerminator()->getNumOperands();
180
181 // Check output types.
182 for (auto [result, arg] :
183 llvm::zip(getResults(), block->getTerminator()->getOperands()))
184 if (result.getType() != arg.getType())
185 return emitOpError("result type ")
186 << result.getType() << " does not match "
187 << "terminator operand type " << arg.getType();
188
189 return success();
190}
assert(baseType &&"element must be base type")
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.