diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index bc8e157e2b1c0..8b069a1f7fe36 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -647,7 +647,11 @@ Improvements to Clang's diagnostics #GH69470, #GH59391, #GH58172, #GH46215, #GH45915, #GH45891, #GH44490, #GH36703, #GH32903, #GH23312, #GH69874. - +- Improved the performance of static assertions involving large integers by + using hex format instead of string for particularly large values. + + Fixes #GH71675 + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 16645ecf411e5..218d50994ed86 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -47,6 +47,7 @@ #include "clang/Sema/SemaOpenMP.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" @@ -17575,7 +17576,8 @@ static bool ConvertAPValueToString(const APValue &V, QualType T, break; } } - V.getInt().toString(Str); + + V.getInt().toStringTruncated(Str); } break; diff --git a/clang/test/AST/ByteCode/intap.cpp b/clang/test/AST/ByteCode/intap.cpp index 68883871ffd26..1381bba5050a2 100644 --- a/clang/test/AST/ByteCode/intap.cpp +++ b/clang/test/AST/ByteCode/intap.cpp @@ -87,12 +87,12 @@ typedef unsigned __int128 uint128_t; static const __uint128_t UINT128_MAX =__uint128_t(__int128_t(-1L)); static_assert(UINT128_MAX == -1, ""); static_assert(UINT128_MAX == 1, ""); // both-error {{static assertion failed}} \ - // both-note {{'340282366920938463463374607431768211455 == 1'}} + // both-note {{'FFFFFFFFFFFFFFFFFFFF...FFFFFFFFFFFFFFFFFFFF == 1'}} static const __int128_t INT128_MAX = UINT128_MAX >> (__int128_t)1; static_assert(INT128_MAX != 0, ""); static_assert(INT128_MAX == 0, ""); // both-error {{failed}} \ - // both-note {{evaluates to '170141183460469231731687303715884105727 == 0'}} + // both-note {{evaluates to '7FFFFFFFFFFFFFFFFFFF...FFFFFFFFFFFFFFFFFFFF == 0'}} static const __int128_t INT128_MIN = -INT128_MAX - 1; @@ -113,14 +113,14 @@ namespace i128 { static const __uint128_t UINT128_MAX =__uint128_t(__int128_t(-1L)); static_assert(UINT128_MAX == -1, ""); static_assert(UINT128_MAX == 1, ""); // both-error {{static assertion failed}} \ - // both-note {{'340282366920938463463374607431768211455 == 1'}} + // both-note {{'FFFFFFFFFFFFFFFFFFFF...FFFFFFFFFFFFFFFFFFFF == 1'}} constexpr uint128_t TooMuch = UINT128_MAX * 2; static const __int128_t INT128_MAX = UINT128_MAX >> (__int128_t)1; static_assert(INT128_MAX != 0, ""); static_assert(INT128_MAX == 0, ""); // both-error {{failed}} \ - // both-note {{evaluates to '170141183460469231731687303715884105727 == 0'}} + // both-note {{evaluates to '7FFFFFFFFFFFFFFFFFFF...FFFFFFFFFFFFFFFFFFFF == 0'}} constexpr int128_t TooMuch2 = INT128_MAX * INT128_MAX; // both-error {{must be initialized by a constant expression}} \ // both-note {{value 28948022309329048855892746252171976962977213799489202546401021394546514198529 is outside the range of representable}} diff --git a/clang/test/SemaCXX/static-assert.cpp b/clang/test/SemaCXX/static-assert.cpp index bf6a2eeb432a3..2488e235d7f7e 100644 --- a/clang/test/SemaCXX/static-assert.cpp +++ b/clang/test/SemaCXX/static-assert.cpp @@ -255,6 +255,16 @@ int f() { } } +namespace GH71675 { +constexpr unsigned _BitInt(__BITINT_MAXWIDTH__ >> 6) F = ~0; // expected-warning {{Clang extension}} +static_assert(F == 1,""); // expected-error {{static assertion failed due to requirement 'F == 1'}} \ + // expected-note {{expression evaluates to '40141321820360630391...65812318570934173695 == 1'}} + +constexpr unsigned _BitInt(__BITINT_MAXWIDTH__) G = ~0; // expected-warning {{Clang extension}} +static_assert(G == 1,""); // expected-error {{static assertion failed due to requirement 'G == 1'}} \ + // expected-note {{expression evaluates to '...85551374411818336255 == 1'}} +} // namespace GH71675 + namespace Diagnostics { /// No notes for literals. static_assert(false, ""); // expected-error {{failed}} diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h index 295506393a1c4..8cc8747bbedcd 100644 --- a/llvm/include/llvm/ADT/APInt.h +++ b/llvm/include/llvm/ADT/APInt.h @@ -1686,6 +1686,17 @@ class [[nodiscard]] APInt { bool UpperCase = true, bool InsertSeparators = false) const; + /// Converts an APInt to a string and append it to Str. Str is commonly a + /// SmallString. If Radix > 10, UpperCase determine the case of letter + /// digits. + /// Very large numbers ar truncated and only the first and last 20 digits will + /// be added with an elipsis separating them. + LLVM_ABI void toStringTruncated(SmallVectorImpl &Str, unsigned Radix, + bool Signed, bool truncate = true, + bool formatAsCLiteral = false, + bool UpperCase = true, + bool InsertSeparators = false) const; + /// Considers the APInt to be unsigned and converts it into a string in the /// radix given. The radix can be 2, 8, 10 16, or 36. void toStringUnsigned(SmallVectorImpl &Str, unsigned Radix = 10) const { diff --git a/llvm/include/llvm/ADT/APSInt.h b/llvm/include/llvm/ADT/APSInt.h index 88a7a6e71c817..f3b5c79569301 100644 --- a/llvm/include/llvm/ADT/APSInt.h +++ b/llvm/include/llvm/ADT/APSInt.h @@ -86,6 +86,12 @@ class [[nodiscard]] APSInt : public APInt { } using APInt::toString; + void toStringTruncated(SmallVectorImpl &Str, + unsigned Radix = 10) const { + APInt::toStringTruncated(Str, Radix, isSigned()); + } + using APInt::toStringTruncated; + /// If this int is representable using an int64_t. bool isRepresentableByInt64() const { // For unsigned values with 64 active bits, they technically fit into a diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp index 954af7fff92a8..37e625c946f9d 100644 --- a/llvm/lib/Support/APInt.cpp +++ b/llvm/lib/Support/APInt.cpp @@ -2164,6 +2164,13 @@ void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) { void APInt::toString(SmallVectorImpl &Str, unsigned Radix, bool Signed, bool formatAsCLiteral, bool UpperCase, bool InsertSeparators) const { + toStringTruncated(Str, Radix, Signed, false, formatAsCLiteral, UpperCase, + InsertSeparators); +} + +void APInt::toStringTruncated(SmallVectorImpl &Str, unsigned Radix, + bool Signed, bool truncate, bool formatAsCLiteral, + bool UpperCase, bool InsertSeparators) const { assert((Radix == 10 || Radix == 8 || Radix == 16 || Radix == 2 || Radix == 36) && "Radix should be 2, 8, 10, 16, or 36!"); @@ -2278,8 +2285,28 @@ void APInt::toString(SmallVectorImpl &Str, unsigned Radix, bool Signed, } } else { int Pos = 0; + // The value of cutOffSize is not special, it is just a number of + // characters that gives us enough info without losing readability. + constexpr int cutOffSize = 20; while (Tmp.getBoolValue()) { uint64_t Digit; + if (truncate && Pos == cutOffSize) { + unsigned numDigits = (int32_t)(Tmp.logBase2()/log2(Radix))+1; + if(numDigits-cutOffSize > 0) { + // Calculating pow of exponents over 300000 takes a long time. + // To keep note printing time short(under 3s), values with more digits + // will only return the last 20 digits. + if(numDigits < 300000) { + APInt divider = APIntOps::pow(APInt(Tmp.getBitWidth(),Radix),numDigits-cutOffSize); + Tmp = Tmp.udiv(divider); + Str.append(3,'.'); + } + else { + Str.append(3,'.'); + break; + } + } + } udivrem(Tmp, Radix, Tmp, Digit); assert(Digit < Radix && "divide failed"); if (InsertSeparators && Pos % Grouping == 0 && Pos > 0)