CIRCT 23.0.0git
Loading...
Searching...
No Matches
FormatInteger.h
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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// Integer formatting shared between the Sim dialect's constant folder and the
10// Arc runtime. Keeping it in a header-only utility lets both produce identical
11// output without the Sim dialect depending on the Arc runtime or vice versa.
12//
13// The formatting follows the SystemVerilog `%d`/`%h`/`%o`/`%b` family. By
14// default a value is padded to the *natural* width of its type -- the number
15// of digits required to print the type's largest value -- so values of the
16// same type line up. An explicit field width overrides this natural width; a
17// field width of 0 disables padding and prints the value in its minimal
18// representation, matching SystemVerilog's `%0d` and friends.
19//
20//===----------------------------------------------------------------------===//
21
22#ifndef CIRCT_SUPPORT_FORMATINTEGER_H
23#define CIRCT_SUPPORT_FORMATINTEGER_H
24
25#include "llvm/ADT/APInt.h"
26#include "llvm/ADT/SmallVector.h"
27#include "llvm/Support/MathExtras.h"
28#include "llvm/Support/raw_ostream.h"
29
30#include <cmath>
31
32namespace circt {
33
34/// Number of decimal digits required to print the largest value of an integer
35/// type of the given bit width.
36inline unsigned getDecimalDigitWidth(unsigned bits, bool isSigned) {
37 if (bits == 0)
38 return 1;
39 if (bits == 1)
40 return isSigned ? 2 : 1;
41 if (isSigned)
42 bits--;
43 // Should be precise up until bits = 13301; log(2) / log(10) + epsilon.
44 const double baseConversionFactor = 0.30103;
45 unsigned digits = std::ceil(bits * baseConversionFactor);
46 return isSigned ? digits + 1 : digits;
47}
48
49/// Natural field width of an integer type printed in the given radix: the
50/// number of digits required to print the type's largest value. `radix` must be
51/// one of {2, 8, 10, 16}.
52inline unsigned getNaturalIntegerWidth(unsigned bits, unsigned radix,
53 bool isSigned) {
54 switch (radix) {
55 case 2:
56 return bits;
57 case 8:
58 return llvm::divideCeil(bits, 3);
59 case 16:
60 return llvm::divideCeil(bits, 4);
61 default: // radix 10
62 return getDecimalDigitWidth(bits, isSigned);
63 }
64}
65
66/// Format `value` in the given `radix` and emit it to `os`, padded to a field
67/// width. The field width defaults to the natural width of the value's type and
68/// is overridden by `specifierWidth` when present; a `specifierWidth` of 0
69/// therefore disables padding. Right-aligned output (the default) is padded on
70/// the leading side with `paddingChar`, matching the SystemVerilog `%d`/`%h`
71/// family. Left-aligned output is padded on the trailing side with spaces,
72/// matching C `printf`, whose zero-pad flag is ignored under left
73/// justification; SystemVerilog's `$display` has no left-aligned form. `radix`
74/// must be one of {2, 8, 10, 16}.
75inline void formatInteger(llvm::raw_ostream &os, const llvm::APInt &value,
76 unsigned radix, bool isUpperCase, bool isLeftAligned,
77 char paddingChar,
78 std::optional<int32_t> specifierWidth,
79 bool isSigned) {
80 llvm::SmallVector<char, 32> digits;
81 value.toString(digits, radix, isSigned, /*formatAsCLiteral=*/false,
82 isUpperCase);
83
84 unsigned fieldWidth =
85 specifierWidth.has_value() && *specifierWidth >= 0
86 ? static_cast<unsigned>(*specifierWidth)
87 : getNaturalIntegerWidth(value.getBitWidth(), radix, isSigned);
88 unsigned padWidth =
89 fieldWidth > digits.size() ? fieldWidth - digits.size() : 0;
90
91 if (isLeftAligned) {
92 llvm::SmallVector<char, 32> padding(padWidth, ' ');
93 os << digits << padding;
94 } else {
95 llvm::SmallVector<char, 32> padding(padWidth, paddingChar);
96 os << padding << digits;
97 }
98}
99
100} // namespace circt
101
102#endif // CIRCT_SUPPORT_FORMATINTEGER_H
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
unsigned getDecimalDigitWidth(unsigned bits, bool isSigned)
Number of decimal digits required to print the largest value of an integer type of the given bit widt...
unsigned getNaturalIntegerWidth(unsigned bits, unsigned radix, bool isSigned)
Natural field width of an integer type printed in the given radix: the number of digits required to p...
void formatInteger(llvm::raw_ostream &os, const llvm::APInt &value, unsigned radix, bool isUpperCase, bool isLeftAligned, char paddingChar, std::optional< int32_t > specifierWidth, bool isSigned)
Format value in the given radix and emit it to os, padded to a field width.