CIRCT 24.0.0git
Loading...
Searching...
No Matches
CombAnalysis.cpp
Go to the documentation of this file.
1//===- CombAnalysis.cpp - Analysis Helpers for Comb+HW 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
11#include "llvm/Support/KnownBits.h"
12
13using namespace circt;
14using namespace comb;
15
16/// Given an integer SSA value, check to see if we know anything about the
17/// result of the computation. For example, we know that "and with a constant"
18/// always returns zeros for the zero bits in a constant.
19///
20/// Expression trees can be very large, so we need to make sure to cap our
21/// recursion, this is controlled by `maxDepth`.
22KnownBits comb::computeKnownBits(Value v, unsigned maxDepth) {
23 Operation *op = v.getDefiningOp();
24 if (!op || maxDepth == 0)
25 return KnownBits(v.getType().getIntOrFloatBitWidth());
26
27 // A constant has all bits known!
28 if (auto constant = dyn_cast<hw::ConstantOp>(op))
29 return KnownBits::makeConstant(constant.getValue());
30
31 // `concat(x, y, z)` has whatever is known about the operands concat'd.
32 if (auto concatOp = dyn_cast<ConcatOp>(op)) {
33 auto result = computeKnownBits(concatOp.getOperand(0), maxDepth - 1);
34 for (size_t i = 1, e = concatOp.getNumOperands(); i != e; ++i) {
35 auto otherBits = computeKnownBits(concatOp.getOperand(i), maxDepth - 1);
36 unsigned width = otherBits.getBitWidth();
37 unsigned newWidth = result.getBitWidth() + width;
38 result.Zero =
39 (result.Zero.zext(newWidth) << width) | otherBits.Zero.zext(newWidth);
40 result.One =
41 (result.One.zext(newWidth) << width) | otherBits.One.zext(newWidth);
42 }
43 return result;
44 }
45
46 // `extract(x from y)` has whatever is known about the extracted bits of the
47 // operand.
48 if (auto extractOp = dyn_cast<ExtractOp>(op)) {
49 unsigned lowBit = extractOp.getLowBit();
50 unsigned width = extractOp.getType().getIntOrFloatBitWidth();
51 // Compute known bits of the input
52 KnownBits inputBits = computeKnownBits(extractOp.getInput(), maxDepth - 1);
53 // Shift down to start at the extract position
54 APInt inputZero = inputBits.Zero.lshr(lowBit);
55 APInt inputOne = inputBits.One.lshr(lowBit);
56
57 // Truncate to the width of the extract result
58 APInt knownZero = inputZero.trunc(width);
59 APInt knownOne = inputOne.trunc(width);
60
61 KnownBits result(width);
62 result.Zero = knownZero;
63 result.One = knownOne;
64 return result;
65 }
66
67 // `and(x, y, z)` has whatever is known about the operands intersected.
68 if (auto andOp = dyn_cast<AndOp>(op)) {
69 auto result = computeKnownBits(andOp.getOperand(0), maxDepth - 1);
70 for (size_t i = 1, e = andOp.getNumOperands(); i != e; ++i)
71 result &= computeKnownBits(andOp.getOperand(i), maxDepth - 1);
72 return result;
73 }
74
75 // `or(x, y, z)` has whatever is known about the operands unioned.
76 if (auto orOp = dyn_cast<OrOp>(op)) {
77 auto result = computeKnownBits(orOp.getOperand(0), maxDepth - 1);
78 for (size_t i = 1, e = orOp.getNumOperands(); i != e; ++i)
79 result |= computeKnownBits(orOp.getOperand(i), maxDepth - 1);
80 return result;
81 }
82
83 // `xor(x, cst)` inverts known bits and passes through unmodified ones.
84 if (auto xorOp = dyn_cast<XorOp>(op)) {
85 auto result = computeKnownBits(xorOp.getOperand(0), maxDepth - 1);
86 for (size_t i = 1, e = xorOp.getNumOperands(); i != e; ++i) {
87 // If we don't know anything, we don't need to evaluate more subexprs.
88 if (result.isUnknown())
89 return result;
90 result ^= computeKnownBits(xorOp.getOperand(i), maxDepth - 1);
91 }
92 return result;
93 }
94
95 // `mux(cond, x, y)` is the intersection of the known bits of `x` and `y`.
96 if (auto muxOp = dyn_cast<MuxOp>(op)) {
97 auto lhs = computeKnownBits(muxOp.getTrueValue(), maxDepth - 1);
98 auto rhs = computeKnownBits(muxOp.getFalseValue(), maxDepth - 1);
99 return lhs.intersectWith(rhs);
100 }
101
102 // `shl(x, y)` is the known bits of `x` << known bits of `y`.
103 if (auto shlOp = dyn_cast<ShlOp>(op)) {
104 auto lhs = computeKnownBits(shlOp.getOperand(0), maxDepth - 1);
105 auto rhs = computeKnownBits(shlOp.getOperand(1), maxDepth - 1);
106 unsigned width = lhs.getBitWidth();
107 if (rhs.getMinValue().uge(width))
108 return KnownBits::makeConstant(APInt::getZero(width));
109 auto res = KnownBits::shl(lhs, rhs);
110 // llvm::KnownBits::shl treats shifts >= bitWidth as UB/poison, whereas
111 // comb.shl produces zero on overshift. If the shift amount may be
112 // >= bitWidth, the result may be zero, so no bit can be known-one.
113 if (rhs.getMaxValue().uge(width))
114 res.One.clearAllBits();
115 return res;
116 }
117
118 // `shr(x, y)` is the known bits of `x` >> known bits of `y`.
119 if (auto shrOp = dyn_cast<ShrUOp>(op)) {
120 auto lhs = computeKnownBits(shrOp.getOperand(0), maxDepth - 1);
121 auto rhs = computeKnownBits(shrOp.getOperand(1), maxDepth - 1);
122 unsigned width = lhs.getBitWidth();
123 if (rhs.getMinValue().uge(width))
124 return KnownBits::makeConstant(APInt::getZero(width));
125 auto res = KnownBits::lshr(lhs, rhs);
126 // llvm::KnownBits::lshr treats shifts >= bitWidth as UB/poison, whereas
127 // comb.shru produces zero on overshift. If the shift amount may be
128 // >= bitWidth, the result may be zero, so no bit can be known-one.
129 if (rhs.getMaxValue().uge(width))
130 res.One.clearAllBits();
131 return res;
132 }
133
134 return KnownBits(v.getType().getIntOrFloatBitWidth());
135}
KnownBits computeKnownBits(Value value, unsigned maxDepth=5)
Compute "known bits" information about the specified value - the set of bits that are guaranteed to a...
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition comb.py:1