diff --git a/include/llvm/ADT/APInt.h b/include/llvm/ADT/APInt.h index 58c9837abf7..707e0dbb6b9 100644 --- a/include/llvm/ADT/APInt.h +++ b/include/llvm/ADT/APInt.h @@ -161,7 +161,7 @@ class APInt { /// not assume that the string is well-formed and (2) grows the /// result to hold the input. /// - /// @param radix 2, 8, 10, or 16 + /// @param radix 2, 8, 10, 16, or 36 /// @brief Convert a char array into an APInt void fromString(unsigned numBits, StringRef str, uint8_t radix); @@ -252,8 +252,8 @@ public: /// This constructor interprets the string \arg str in the given radix. The /// interpretation stops when the first character that is not suitable for the /// radix is encountered, or the end of the string. Acceptable radix values - /// are 2, 8, 10 and 16. It is an error for the value implied by the string to - /// require more bits than numBits. + /// are 2, 8, 10, 16, and 36. It is an error for the value implied by the + /// string to require more bits than numBits. /// /// @param numBits the bit width of the constructed APInt /// @param str the string to be interpreted @@ -1257,13 +1257,13 @@ public: bool formatAsCLiteral = 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 or 16. + /// radix given. The radix can be 2, 8, 10 16, or 36. void toStringUnsigned(SmallVectorImpl &Str, unsigned Radix = 10) const { toString(Str, Radix, false, false); } /// Considers the APInt to be signed and converts it into a string in the - /// radix given. The radix can be 2, 8, 10 or 16. + /// radix given. The radix can be 2, 8, 10, 16, or 36. void toStringSigned(SmallVectorImpl &Str, unsigned Radix = 10) const { toString(Str, Radix, true, false); } diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index 0b2536031f1..3cb75762790 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -48,17 +48,17 @@ inline static uint64_t* getMemory(unsigned numWords) { inline static unsigned getDigit(char cdigit, uint8_t radix) { unsigned r; - if (radix == 16) { + if (radix == 16 || radix == 36) { r = cdigit - '0'; if (r <= 9) return r; r = cdigit - 'A'; - if (r <= 5) + if (r <= radix-11) return r + 10; r = cdigit - 'a'; - if (r <= 5) + if (r <= radix-11) return r + 10; } @@ -621,8 +621,9 @@ void APInt::flipBit(unsigned bitPosition) { unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) { assert(!str.empty() && "Invalid string length"); - assert((radix == 10 || radix == 8 || radix == 16 || radix == 2) && - "Radix should be 2, 8, 10, or 16!"); + assert((radix == 10 || radix == 8 || radix == 16 || radix == 2 || + radix == 36) && + "Radix should be 2, 8, 10, 16, or 36!"); size_t slen = str.size(); @@ -644,6 +645,8 @@ unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) { if (radix == 16) return slen * 4 + isNegative; + // FIXME: base 36 + // This is grossly inefficient but accurate. We could probably do something // with a computation of roughly slen*64/20 and then adjust by the value of // the first few digits. But, I'm not sure how accurate that could be. @@ -652,7 +655,9 @@ unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) { // be too large. This avoids the assertion in the constructor. This // calculation doesn't work appropriately for the numbers 0-9, so just use 4 // bits in that case. - unsigned sufficient = slen == 1 ? 4 : slen * 64/18; + unsigned sufficient + = radix == 10? (slen == 1 ? 4 : slen * 64/18) + : (slen == 1 ? 7 : slen * 16/3); // Convert to the actual binary value. APInt tmp(sufficient, StringRef(p, slen), radix); @@ -2115,8 +2120,9 @@ APInt APInt::sshl_ov(unsigned ShAmt, bool &Overflow) const { void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) { // Check our assumptions here assert(!str.empty() && "Invalid string length"); - assert((radix == 10 || radix == 8 || radix == 16 || radix == 2) && - "Radix should be 2, 8, 10, or 16!"); + assert((radix == 10 || radix == 8 || radix == 16 || radix == 2 || + radix == 36) && + "Radix should be 2, 8, 10, 16, or 36!"); StringRef::iterator p = str.begin(); size_t slen = str.size(); @@ -2173,7 +2179,8 @@ void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) { void APInt::toString(SmallVectorImpl &Str, unsigned Radix, bool Signed, bool formatAsCLiteral) const { - assert((Radix == 10 || Radix == 8 || Radix == 16 || Radix == 2) && + assert((Radix == 10 || Radix == 8 || Radix == 16 || Radix == 2 || + Radix == 36) && "Radix should be 2, 8, 10, or 16!"); const char *Prefix = ""; @@ -2203,7 +2210,7 @@ void APInt::toString(SmallVectorImpl &Str, unsigned Radix, return; } - static const char Digits[] = "0123456789ABCDEF"; + static const char Digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; if (isSingleWord()) { char Buffer[65]; @@ -2257,7 +2264,7 @@ void APInt::toString(SmallVectorImpl &Str, unsigned Radix, // For the 2, 8 and 16 bit cases, we can just shift instead of divide // because the number of bits per digit (1, 3 and 4 respectively) divides // equaly. We just shift until the value is zero. - if (Radix != 10) { + if (Radix == 2 || Radix == 8 || Radix == 16) { // Just shift tmp right for each digit width until it becomes zero unsigned ShiftAmt = (Radix == 16 ? 4 : (Radix == 8 ? 3 : 1)); unsigned MaskAmt = Radix - 1; @@ -2268,7 +2275,7 @@ void APInt::toString(SmallVectorImpl &Str, unsigned Radix, Tmp = Tmp.lshr(ShiftAmt); } } else { - APInt divisor(4, 10); + APInt divisor(Radix == 10? 4 : 8, Radix); while (Tmp != 0) { APInt APdigit(1, 0); APInt tmp2(Tmp.getBitWidth(), 0); diff --git a/unittests/ADT/APIntTest.cpp b/unittests/ADT/APIntTest.cpp index c9b3bc51c13..11bb5e15455 100644 --- a/unittests/ADT/APIntTest.cpp +++ b/unittests/ADT/APIntTest.cpp @@ -237,6 +237,20 @@ TEST(APIntTest, fromString) { EXPECT_EQ(APInt(32, uint64_t(-16LL)), APInt(32, "-10", 16)); EXPECT_EQ(APInt(32, uint64_t(-31LL)), APInt(32, "-1F", 16)); EXPECT_EQ(APInt(32, uint64_t(-32LL)), APInt(32, "-20", 16)); + + EXPECT_EQ(APInt(32, 0), APInt(32, "0", 36)); + EXPECT_EQ(APInt(32, 1), APInt(32, "1", 36)); + EXPECT_EQ(APInt(32, 35), APInt(32, "Z", 36)); + EXPECT_EQ(APInt(32, 36), APInt(32, "10", 36)); + EXPECT_EQ(APInt(32, 71), APInt(32, "1Z", 36)); + EXPECT_EQ(APInt(32, 72), APInt(32, "20", 36)); + + EXPECT_EQ(APInt(32, uint64_t(-0LL)), APInt(32, "-0", 36)); + EXPECT_EQ(APInt(32, uint64_t(-1LL)), APInt(32, "-1", 36)); + EXPECT_EQ(APInt(32, uint64_t(-35LL)), APInt(32, "-Z", 36)); + EXPECT_EQ(APInt(32, uint64_t(-36LL)), APInt(32, "-10", 36)); + EXPECT_EQ(APInt(32, uint64_t(-71LL)), APInt(32, "-1Z", 36)); + EXPECT_EQ(APInt(32, uint64_t(-72LL)), APInt(32, "-20", 36)); } TEST(APIntTest, FromArray) { @@ -340,6 +354,9 @@ TEST(APIntTest, toString) { APInt(8, 0).toString(S, 16, true, true); EXPECT_EQ(S.str().str(), "0x0"); S.clear(); + APInt(8, 0).toString(S, 36, true, true); + EXPECT_EQ(S.str().str(), "0"); + S.clear(); isSigned = false; APInt(8, 255, isSigned).toString(S, 2, isSigned, true); @@ -354,6 +371,9 @@ TEST(APIntTest, toString) { APInt(8, 255, isSigned).toString(S, 16, isSigned, true); EXPECT_EQ(S.str().str(), "0xFF"); S.clear(); + APInt(8, 255, isSigned).toString(S, 36, isSigned, true); + EXPECT_EQ(S.str().str(), "73"); + S.clear(); isSigned = true; APInt(8, 255, isSigned).toString(S, 2, isSigned, true); @@ -368,6 +388,9 @@ TEST(APIntTest, toString) { APInt(8, 255, isSigned).toString(S, 16, isSigned, true); EXPECT_EQ(S.str().str(), "-0x1"); S.clear(); + APInt(8, 255, isSigned).toString(S, 36, isSigned, true); + EXPECT_EQ(S.str().str(), "-1"); + S.clear(); } TEST(APIntTest, Log2) { @@ -407,7 +430,7 @@ TEST(APIntTest, magicu) { TEST(APIntTest, StringDeath) { EXPECT_DEATH(APInt(0, "", 0), "Bitwidth too small"); EXPECT_DEATH(APInt(32, "", 0), "Invalid string length"); - EXPECT_DEATH(APInt(32, "0", 0), "Radix should be 2, 8, 10, or 16!"); + EXPECT_DEATH(APInt(32, "0", 0), "Radix should be 2, 8, 10, 16, or 36!"); EXPECT_DEATH(APInt(32, "", 10), "Invalid string length"); EXPECT_DEATH(APInt(32, "-", 10), "String is only a sign, needs a value."); EXPECT_DEATH(APInt(1, "1234", 10), "Insufficient bit width");