CIRCT  20.0.0git
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 
14 #include "circt/Dialect/HW/HWOps.h"
15 #include "mlir/IR/PatternMatch.h"
16 
17 using namespace mlir;
18 using namespace circt;
19 using namespace circt::aig;
20 
21 #define GET_OP_CLASSES
22 #include "circt/Dialect/AIG/AIG.cpp.inc"
23 
24 OpFoldResult AndInverterOp::fold(FoldAdaptor adaptor) {
25  if (getNumOperands() == 1 && !isInverted(0))
26  return getOperand(0);
27  return {};
28 }
29 
30 LogicalResult 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 
95 ParseResult 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 
123 void 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 
137 APInt 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 
151 LogicalResult 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")
static LogicalResult canonicalize(Op op, PatternRewriter &rewriter)
Definition: VerifOps.cpp:66
static LogicalResult verify(Value clock, bool eventExists, mlir::Location loc)
Definition: SVOps.cpp:2467
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21