CIRCT 20.0.0git
Loading...
Searching...
No Matches
FVInt.cpp
Go to the documentation of this file.
1//===- FVInt.cpp - Four-valued integer --------------------------*- 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
10#include "mlir/IR/OpImplementation.h"
11#include "llvm/ADT/StringExtras.h"
12
13#define DEBUG_TYPE "fvint"
14
15using namespace circt;
16
17std::optional<FVInt> FVInt::tryFromString(StringRef str, unsigned radix) {
18 assert(radix == 2 || radix == 8 || radix == 10 || radix == 16);
19 if (str.empty())
20 return {};
21
22 // Overestimate the number of bits that will be needed to hold all digits.
23 unsigned radixLog2 = 0;
24 for (unsigned r = radix - 1; r > 0; r >>= 1)
25 ++radixLog2;
26 bool radixIsPow2 = (radix == (1U << radixLog2));
27
28 // Parse the string.
29 auto result = FVInt::getZero(str.size() * radixLog2);
30 while (!str.empty()) {
31 unsigned digit = llvm::toLower(str[0]);
32 str = str.drop_front();
33
34 // Handle X and Z digits.
35 if (digit == 'x' || digit == 'z') {
36 if (!radixIsPow2)
37 return {};
38 result <<= radixLog2;
39 result.unknown.setLowBits(radixLog2);
40 if (digit == 'z')
41 result.value.setLowBits(radixLog2);
42 continue;
43 }
44
45 // Determine the value of the current digit.
46 if (digit >= '0' && digit <= '9')
47 digit = digit - '0';
48 else if (digit >= 'a' && digit <= 'z')
49 digit = digit - 'a' + 10;
50 else
51 return {};
52 if (digit >= radix)
53 return {};
54
55 // Add the digit to the result.
56 if (radixIsPow2) {
57 result <<= radixLog2;
58 result.value |= digit;
59 } else {
60 result.value *= radix;
61 result.value += digit;
62 }
63 }
64
65 return result;
66}
67
68bool FVInt::tryToString(SmallVectorImpl<char> &str, unsigned radix,
69 bool uppercase) const {
70 size_t strBaseLen = str.size();
71 assert(radix == 2 || radix == 8 || radix == 10 || radix == 16);
72
73 // Determine if the radix is a power of two.
74 unsigned radixLog2 = 0;
75 for (unsigned r = radix - 1; r > 0; r >>= 1)
76 ++radixLog2;
77 bool radixIsPow2 = (radix == (1U << radixLog2));
78 unsigned radixMask = (1U << radixLog2) - 1;
79
80 // If the number has no X or Z bits, take the easy route and print the `APInt`
81 // directly.
82 if (!hasUnknown()) {
83 value.toString(str, radix, /*Signed=*/false, /*formatAsCLiteral=*/false,
84 uppercase);
85 return true;
86 }
87
88 // We can only print with non-power-of-two radices if there are no X or Z
89 // bits. So at this point we require radix be a power of two.
90 if (!radixIsPow2)
91 return false;
92
93 // Otherwise chop off digits at the bottom and print them to the string. This
94 // prints the digits in reverse order, with the least significant digit as the
95 // first character.
96 APInt value = this->value;
97 APInt unknown = this->unknown;
98
99 char chrA = uppercase ? 'A' : 'a';
100 char chrX = uppercase ? 'X' : 'x';
101 char chrZ = uppercase ? 'Z' : 'z';
102
103 while (!value.isZero() || !unknown.isZero()) {
104 unsigned digitValue = value.getRawData()[0] & radixMask;
105 unsigned digitUnknown = unknown.getRawData()[0] & radixMask;
106 unsigned shiftAmount = std::min(radixLog2, getBitWidth());
107 value.lshrInPlace(shiftAmount);
108 unknown.lshrInPlace(shiftAmount);
109
110 // Handle unknown bits. Since we only get to print a single X or Z character
111 // to the string, either all bits in the digit have to be X, or all have to
112 // be Z. But we cannot represent the case where X, Z and 0/1 bits are mixed.
113 if (digitUnknown != 0) {
114 if (digitUnknown != radixMask ||
115 (digitValue != 0 && digitValue != radixMask)) {
116 str.resize(strBaseLen);
117 return false;
118 }
119 str.push_back(digitValue == 0 ? chrX : chrZ);
120 continue;
121 }
122
123 // Handle known bits.
124 if (digitValue < 10)
125 str.push_back(digitValue + '0');
126 else
127 str.push_back(digitValue - 10 + chrA);
128 }
129
130 // Reverse the digits.
131 std::reverse(str.begin() + strBaseLen, str.end());
132 return true;
133}
134
135void FVInt::print(raw_ostream &os) const {
136 SmallString<32> buffer;
137 if (!tryToString(buffer))
138 if (!tryToString(buffer, 16))
139 tryToString(buffer, 2);
140 os << buffer;
141}
142
143llvm::hash_code circt::hash_value(const FVInt &a) {
144 return llvm::hash_combine(a.getRawValue(), a.getRawUnknown());
145}
146
147void circt::printFVInt(AsmPrinter &p, const FVInt &value) {
148 SmallString<32> buffer;
149 if (value.getBitWidth() > 1 && value.isNegative() &&
150 (-value).tryToString(buffer)) {
151 p << "-" << buffer;
152 } else if (value.tryToString(buffer)) {
153 p << buffer;
154 } else if (value.tryToString(buffer, 16)) {
155 p << "h" << buffer;
156 } else {
157 value.tryToString(buffer, 2);
158 p << "b" << buffer;
159 }
160}
161
162ParseResult circt::parseFVInt(AsmParser &p, FVInt &result) {
163 // Parse the value as either a keyword (`b[01XZ]+` for binary or
164 // `h[0-9A-FXZ]+` for hexadecimal), or an integer value (for decimal).
165 FVInt value;
166 StringRef strValue;
167 auto valueLoc = p.getCurrentLocation();
168 if (succeeded(p.parseOptionalKeyword(&strValue))) {
169 // Determine the radix based on the `b` or `h` prefix.
170 unsigned base = 0;
171 if (strValue.consume_front("b")) {
172 base = 2;
173 } else if (strValue.consume_front("h")) {
174 base = 16;
175 } else {
176 return p.emitError(valueLoc) << "expected `b` or `h` prefix";
177 }
178
179 // Parse the value.
180 auto parsedValue = FVInt::tryFromString(strValue, base);
181 if (!parsedValue) {
182 return p.emitError(valueLoc)
183 << "expected base-" << base << " four-valued integer";
184 }
185
186 // Add a zero bit at the top to ensure the value reads as positive.
187 result = parsedValue->zext(parsedValue->getBitWidth() + 1);
188 } else {
189 APInt intValue;
190 if (p.parseInteger(intValue))
191 return failure();
192 result = std::move(intValue);
193 }
194 return success();
195}
196
197unsigned DenseMapInfo<FVInt, void>::getHashValue(const FVInt &Key) {
198 return static_cast<unsigned>(hash_value(Key));
199}
assert(baseType &&"element must be base type")
Four-valued arbitrary precision integers.
Definition FVInt.h:37
static FVInt getZero(unsigned numBits)
Construct an FVInt with all bits set to 0.
Definition FVInt.h:61
APInt value
Definition FVInt.h:628
bool isNegative() const
Determine whether the integer interpreted as a signed number would be negative.
Definition FVInt.h:181
APInt unknown
Definition FVInt.h:629
static std::optional< FVInt > tryFromString(StringRef str, unsigned radix=10)
Convert a string into an FVInt.
Definition FVInt.cpp:17
const APInt & getRawValue() const
Return the underlying APInt used to store whether a bit is 0/X or 1/Z.
Definition FVInt.h:103
const APInt & getRawUnknown() const
Return the underlying APInt used to store whether a bit is unknown (X or Z).
Definition FVInt.h:107
void print(raw_ostream &os) const
Print an FVInt to an output stream.
Definition FVInt.cpp:135
bool hasUnknown() const
Determine if any bits are X or Z.
Definition FVInt.h:164
FVInt zext(unsigned bitWidth) const
Zero-extend the integer to a new bit width.
Definition FVInt.h:135
unsigned getBitWidth() const
Return the number of bits this integer has.
Definition FVInt.h:81
bool tryToString(SmallVectorImpl< char > &str, unsigned radix=10, bool uppercase=true) const
Convert an FVInt to a string.
Definition FVInt.cpp:68
static llvm::hash_code hash_value(const ModulePort &port)
Definition HWTypes.h:38
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void printFVInt(AsmPrinter &p, const FVInt &value)
Print a four-valued integer usign an AsmPrinter.
Definition FVInt.cpp:147
ParseResult parseFVInt(AsmParser &p, FVInt &result)
Parse a four-valued integer using an AsmParser.
Definition FVInt.cpp:162