CIRCT 22.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
17#include "mlir/IR/PatternMatch.h"
18
19using namespace mlir;
20using namespace circt;
21using namespace circt::aig;
22
23#define GET_OP_CLASSES
24#include "circt/Dialect/AIG/AIG.cpp.inc"
25
26OpFoldResult AndInverterOp::fold(FoldAdaptor adaptor) {
27 if (getNumOperands() == 1 && !isInverted(0))
28 return getOperand(0);
29 return {};
30}
31
32LogicalResult AndInverterOp::canonicalize(AndInverterOp op,
33 PatternRewriter &rewriter) {
35 SmallVector<Value> uniqueValues;
36 SmallVector<bool> uniqueInverts;
37
38 APInt constValue =
39 APInt::getAllOnes(op.getResult().getType().getIntOrFloatBitWidth());
40
41 bool invertedConstFound = false;
42 bool flippedFound = false;
43
44 for (auto [value, inverted] : llvm::zip(op.getInputs(), op.getInverted())) {
45 bool newInverted = inverted;
46 if (auto constOp = value.getDefiningOp<hw::ConstantOp>()) {
47 if (inverted) {
48 constValue &= ~constOp.getValue();
49 invertedConstFound = true;
50 } else {
51 constValue &= constOp.getValue();
52 }
53 continue;
54 }
55
56 if (auto andInverterOp = value.getDefiningOp<aig::AndInverterOp>()) {
57 if (andInverterOp.getInputs().size() == 1 &&
58 andInverterOp.isInverted(0)) {
59 value = andInverterOp.getOperand(0);
60 newInverted = andInverterOp.isInverted(0) ^ inverted;
61 flippedFound = true;
62 }
63 }
64
65 auto it = seen.find(value);
66 if (it == seen.end()) {
67 seen.insert({value, newInverted});
68 uniqueValues.push_back(value);
69 uniqueInverts.push_back(newInverted);
70 } else if (it->second != newInverted) {
71 // replace with const 0
72 rewriter.replaceOpWithNewOp<hw::ConstantOp>(
73 op, APInt::getZero(value.getType().getIntOrFloatBitWidth()));
74 return success();
75 }
76 }
77
78 // If the constant is zero, we can just replace with zero.
79 if (constValue.isZero()) {
80 rewriter.replaceOpWithNewOp<hw::ConstantOp>(op, constValue);
81 return success();
82 }
83
84 // No change.
85 if ((uniqueValues.size() == op.getInputs().size() && !flippedFound) ||
86 (!constValue.isAllOnes() && !invertedConstFound &&
87 uniqueValues.size() + 1 == op.getInputs().size()))
88 return failure();
89
90 if (!constValue.isAllOnes()) {
91 auto constOp = hw::ConstantOp::create(rewriter, op.getLoc(), constValue);
92 uniqueInverts.push_back(false);
93 uniqueValues.push_back(constOp);
94 }
95
96 // It means the input is reduced to all ones.
97 if (uniqueValues.empty()) {
98 rewriter.replaceOpWithNewOp<hw::ConstantOp>(op, constValue);
99 return success();
100 }
101
102 // build new op with reduced input values
103 replaceOpWithNewOpAndCopyNamehint<aig::AndInverterOp>(
104 rewriter, op, uniqueValues, uniqueInverts);
105 return success();
106}
107
108APInt AndInverterOp::evaluate(ArrayRef<APInt> inputs) {
109 assert(inputs.size() == getNumOperands() &&
110 "Expected as many inputs as operands");
111 assert(!inputs.empty() && "Expected non-empty input list");
112 APInt result = APInt::getAllOnes(inputs.front().getBitWidth());
113 for (auto [idx, input] : llvm::enumerate(inputs)) {
114 if (isInverted(idx))
115 result &= ~input;
116 else
117 result &= input;
118 }
119 return result;
120}
121
122static Value lowerVariadicAndInverterOp(aig::AndInverterOp op,
123 OperandRange operands,
124 ArrayRef<bool> inverts,
125 PatternRewriter &rewriter) {
126 using namespace aig;
127 switch (operands.size()) {
128 case 0:
129 assert(0 && "cannot be called with empty operand range");
130 break;
131 case 1:
132 if (inverts[0])
133 return AndInverterOp::create(rewriter, op.getLoc(), operands[0], true);
134 else
135 return operands[0];
136 case 2:
137 return AndInverterOp::create(rewriter, op.getLoc(), operands[0],
138 operands[1], inverts[0], inverts[1]);
139 default:
140 auto firstHalf = operands.size() / 2;
141 auto lhs =
142 lowerVariadicAndInverterOp(op, operands.take_front(firstHalf),
143 inverts.take_front(firstHalf), rewriter);
144 auto rhs =
145 lowerVariadicAndInverterOp(op, operands.drop_front(firstHalf),
146 inverts.drop_front(firstHalf), rewriter);
147 return AndInverterOp::create(rewriter, op.getLoc(), lhs, rhs);
148 }
149
150 return Value();
151}
152
154 aig::AndInverterOp op, PatternRewriter &rewriter) const {
155 if (op.getInputs().size() <= 2)
156 return failure();
157
158 // TODO: This is a naive implementation that creates a balanced binary tree.
159 // We can improve by analyzing the dataflow and creating a tree that
160 // improves the critical path or area.
161 rewriter.replaceOp(op, lowerVariadicAndInverterOp(
162 op, op.getOperands(), op.getInverted(), rewriter));
163 return success();
164}
static Value lowerVariadicAndInverterOp(aig::AndInverterOp op, OperandRange operands, ArrayRef< bool > inverts, PatternRewriter &rewriter)
Definition AIGOps.cpp:122
assert(baseType &&"element must be base type")
create(data_type, value)
Definition hw.py:433
Definition aig.py:1
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
mlir::LogicalResult matchAndRewrite(circt::aig::AndInverterOp op, mlir::PatternRewriter &rewriter) const override
Definition AIGOps.cpp:153