[llvm] [llvm]: tighten estimate of bits needed when parsing an integer (PR #205947)
Jeremy Kun via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 25 16:11:57 PDT 2026
https://github.com/j2kun created https://github.com/llvm/llvm-project/pull/205947
A colleague of mine noticed that `"12535824225335233"` parses in MLIR's integer attribute parser as a 68-bit integer, even though it is a 53-bit constant. I traced this back to `StringRef::consumeInteger`'s heuristic estimate of the bit size. This change tightens that estimate to at most a 1-bit overapproximation.
>From f60b433455657855f547b9d5a7785e8817f4caf0 Mon Sep 17 00:00:00 2001
From: Jeremy Kun <jkun at google.com>
Date: Thu, 25 Jun 2026 16:10:09 -0700
Subject: [PATCH] [llvm]: tighten estimate of bits needed when parsing an
integer
---
llvm/lib/Support/StringRef.cpp | 17 +++++++++++++-
llvm/unittests/ADT/StringRefTest.cpp | 35 ++++++++++++++++++++++++++++
2 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Support/StringRef.cpp b/llvm/lib/Support/StringRef.cpp
index 02270a6e223af..f62b6e602ccfd 100644
--- a/llvm/lib/Support/StringRef.cpp
+++ b/llvm/lib/Support/StringRef.cpp
@@ -527,7 +527,22 @@ bool StringRef::consumeInteger(unsigned Radix, APInt &Result) {
while ((1U << Log2Radix) < Radix) Log2Radix++;
bool IsPowerOf2Radix = ((1U << Log2Radix) == Radix);
- unsigned BitWidth = Log2Radix * Str.size();
+ // (Over-)estimate the required number of bits tightly using a Q10 fixed-point
+ // approximation of log2(Radix) to avoid massive over-allocation for large
+ // non-power-of-two values (e.g. decimal).
+ unsigned BitWidth = 0;
+ if (Radix <= 36) {
+ static const uint16_t Log2RadixTable[] = {
+ 0, 0,
+ 1024, 1624, 2048, 2378, 2648, 2875, 3072, 3247, 3402, // 2..10
+ 3543, 3672, 3790, 3899, 4001, 4096, 4186, 4271, 4350, // 11..19
+ 4426, 4498, 4567, 4633, 4696, 4756, 4814, 4870, 4923, // 20..28
+ 4975, 5025, 5074, 5120, 5166, 5210, 5253, 5295 // 29..36
+ };
+ BitWidth = (Str.size() * Log2RadixTable[Radix] + 1023) >> 10;
+ } else {
+ BitWidth = Log2Radix * Str.size();
+ }
if (BitWidth < Result.getBitWidth())
BitWidth = Result.getBitWidth(); // don't shrink the result
else if (BitWidth > Result.getBitWidth())
diff --git a/llvm/unittests/ADT/StringRefTest.cpp b/llvm/unittests/ADT/StringRefTest.cpp
index cca0f3a2b46b0..db9c67c7f742f 100644
--- a/llvm/unittests/ADT/StringRefTest.cpp
+++ b/llvm/unittests/ADT/StringRefTest.cpp
@@ -968,6 +968,41 @@ TEST(StringRefTest, consumeIntegerSigned) {
}
}
+TEST(StringRefTest, consumeIntegerAPIntBitWidth) {
+ // Decimal large number (12535824225335233)
+ // 17 digits, (17 * 3402 + 1023) >> 10 = 57 bits.
+ {
+ APInt U;
+ StringRef Str = "12535824225335233";
+ bool Success = Str.consumeInteger(10, U);
+ ASSERT_FALSE(Success);
+ EXPECT_EQ(U.getZExtValue(), 12535824225335233ULL);
+ EXPECT_EQ(U.getBitWidth(), 57U);
+ }
+
+ // Hex version of same number (2c894405eaf7c1)
+ // 14 digits, (14 * 4096 + 1023) >> 10 = 56 bits.
+ {
+ APInt U;
+ StringRef Str = "2c894405eaf7c1";
+ bool Success = Str.consumeInteger(16, U);
+ ASSERT_FALSE(Success);
+ EXPECT_EQ(U.getZExtValue(), 12535824225335233ULL);
+ EXPECT_EQ(U.getBitWidth(), 56U);
+ }
+
+ // A very large decimal number (100 digits)
+ // (100 * 3402 + 1023) >> 10 = 333 bits.
+ {
+ APInt U;
+ std::string LargeDec(100, '9');
+ StringRef Str = LargeDec;
+ bool Success = Str.consumeInteger(10, U);
+ ASSERT_FALSE(Success);
+ EXPECT_EQ(U.getBitWidth(), 333U);
+ }
+}
+
struct GetDoubleStrings {
const char *Str;
bool AllowInexact;
More information about the llvm-commits
mailing list