From fad86b003a839cef40ec8ce8408322f4913368ca Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 17 Aug 2008 07:19:36 +0000 Subject: [PATCH] Rework the routines that convert AP[S]Int into a string. Now, instead of returning an std::string by value, it fills in a SmallString/SmallVector passed in. This significantly reduces string thrashing in some cases. More specifically, this: - Adds an operator<< and a print method for APInt that allows you to directly send them to an ostream. - Reimplements APInt::toString to be much simpler and more efficient algorithmically in addition to not thrashing strings quite as much. This speeds up llvm-dis on kc++ by 7%, and may also slightly speed up the asmprinter. This also fixes a bug I introduced into the asmwriter in a previous patch w.r.t. alias printing. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@54873 91177308-0d34-0410-b5e6-96231b3b80d8 --- examples/Fibonacci/fibonacci.cpp | 2 +- examples/HowToUseJIT/HowToUseJIT.cpp | 2 +- include/llvm/ADT/APInt.h | 37 ++-- include/llvm/ADT/APSInt.h | 18 +- lib/AsmParser/ParserInternals.h | 2 +- lib/CodeGen/AsmPrinter.cpp | 15 +- lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 2 +- lib/Support/APFloat.cpp | 3 +- lib/Support/APInt.cpp | 195 +++++++++++----------- lib/Support/ConstantRange.cpp | 3 +- lib/Target/CppBackend/CPPBackend.cpp | 4 +- lib/Transforms/Utils/LowerSwitch.cpp | 8 +- lib/VMCore/AsmWriter.cpp | 19 ++- 13 files changed, 170 insertions(+), 140 deletions(-) diff --git a/examples/Fibonacci/fibonacci.cpp b/examples/Fibonacci/fibonacci.cpp index 73dff11031c..f4c5c3d698a 100644 --- a/examples/Fibonacci/fibonacci.cpp +++ b/examples/Fibonacci/fibonacci.cpp @@ -116,6 +116,6 @@ int main(int argc, char **argv) { GenericValue GV = EE->runFunction(FibF, Args); // import result of execution - std::cout << "Result: " << GV.IntVal.toStringUnsigned(10) << "\n"; + std::cout << "Result: " << GV.IntVal << "\n"; return 0; } diff --git a/examples/HowToUseJIT/HowToUseJIT.cpp b/examples/HowToUseJIT/HowToUseJIT.cpp index 5fa4237179f..d50000579ef 100644 --- a/examples/HowToUseJIT/HowToUseJIT.cpp +++ b/examples/HowToUseJIT/HowToUseJIT.cpp @@ -107,6 +107,6 @@ int main() { GenericValue gv = EE->runFunction(FooF, noargs); // Import result of execution: - std::cout << "Result: " << gv.IntVal.toStringUnsigned(10) << "\n"; + std::cout << "Result: " << gv.IntVal << "\n"; return 0; } diff --git a/include/llvm/ADT/APInt.h b/include/llvm/ADT/APInt.h index 9e8119d7a36..c475cf3f71c 100644 --- a/include/llvm/ADT/APInt.h +++ b/include/llvm/ADT/APInt.h @@ -17,6 +17,7 @@ #include "llvm/Support/DataTypes.h" #include +#include #include namespace llvm { @@ -24,6 +25,9 @@ namespace llvm { class Deserializer; class FoldingSetNodeID; + template + class SmallVectorImpl; + /* An unsigned host type used as a single part of a multi-part bignum. */ typedef uint64_t integerPart; @@ -468,7 +472,7 @@ public: /// Performs logical negation operation on this APInt. /// @returns true if *this is zero, false otherwise. /// @brief Logical negation operator. - bool operator !() const; + bool operator!() const; /// @} /// @name Assignment Operators @@ -972,25 +976,29 @@ public: /// @name Conversion Functions /// @{ - /// This is used internally to convert an APInt to a string. - /// @brief Converts an APInt to a std::string - std::string toString(uint8_t radix, bool wantSigned) const; + void print(std::ostream &OS, bool isSigned) const; + + /// toString - Converts an APInt to a string and append it to Str. Str is + /// commonly a SmallString. + void toString(SmallVectorImpl &Str, unsigned Radix, bool Signed) 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. - /// @returns a character interpretation of the APInt - /// @brief Convert unsigned APInt to string representation. - std::string toStringUnsigned(uint8_t radix = 10) const { - return toString(radix, false); + void toStringUnsigned(SmallVectorImpl &Str, unsigned Radix = 10) const { + return toString(Str, Radix, 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. - /// @returns a character interpretation of the APInt - /// @brief Convert signed APInt to string representation. - std::string toStringSigned(uint8_t radix = 10) const { - return toString(radix, true); + void toStringSigned(SmallVectorImpl &Str, unsigned Radix = 10) const { + return toString(Str, Radix, true); } + + /// toString - This returns the APInt as a std::string. Note that this is an + /// inefficient method. It is better to pass in a SmallVector/SmallString + /// to the methods above to avoid thrashing the heap for the string. + std::string toString(unsigned Radix, bool Signed) const; + /// @returns a byte-swapped representation of this APInt Value. APInt byteSwap() const; @@ -1237,6 +1245,11 @@ inline bool operator!=(uint64_t V1, const APInt& V2) { return V2 != V1; } +inline std::ostream &operator<<(std::ostream &OS, const APInt &I) { + I.print(OS, true); + return OS; +} + namespace APIntOps { /// @brief Determine the smaller of two APInts considered to be signed. diff --git a/include/llvm/ADT/APSInt.h b/include/llvm/ADT/APSInt.h index edb36bafe4a..00bece62ade 100644 --- a/include/llvm/ADT/APSInt.h +++ b/include/llvm/ADT/APSInt.h @@ -19,7 +19,6 @@ namespace llvm { - class APSInt : public APInt { bool IsUnsigned; public: @@ -58,11 +57,16 @@ public: void setIsUnsigned(bool Val) { IsUnsigned = Val; } void setIsSigned(bool Val) { IsUnsigned = !Val; } - /// This is used internally to convert an APInt to a string. - /// @brief Converts an APInt to a std::string - std::string toString(uint8_t Radix = 10) const { + /// toString - Append this APSInt to the specified SmallString. + void toString(SmallVectorImpl &Str, unsigned Radix = 10) const { + return APInt::toString(Str, Radix, isSigned()); + } + /// toString - Converts an APInt to a std::string. This is an inefficient + /// method, your should prefer passing in a SmallString instead. + std::string toString(unsigned Radix) const { return APInt::toString(Radix, isSigned()); } + using APInt::toString; APSInt& extend(uint32_t width) { if (IsUnsigned) @@ -235,6 +239,12 @@ public: void Profile(FoldingSetNodeID& ID) const; }; +inline std::ostream &operator<<(std::ostream &OS, const APSInt &I) { + I.print(OS, I.isSigned()); + return OS; +} + + } // end namespace llvm #endif diff --git a/lib/AsmParser/ParserInternals.h b/lib/AsmParser/ParserInternals.h index aae1d53535a..cc35038a418 100644 --- a/lib/AsmParser/ParserInternals.h +++ b/lib/AsmParser/ParserInternals.h @@ -170,7 +170,7 @@ struct ValID { case GlobalID : return '@' + utostr(Num); case LocalName : return *Name; case GlobalName : return *Name; - case ConstAPInt : return ConstPoolInt->toString(); + case ConstAPInt : return ConstPoolInt->toString(10); case ConstFPVal : return ftostr(*ConstPoolFP); case ConstNullVal : return "null"; case ConstUndefVal : return "undef"; diff --git a/lib/CodeGen/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter.cpp index 16f26c42992..1bc4868a608 100644 --- a/lib/CodeGen/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter.cpp @@ -31,6 +31,7 @@ #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" #include using namespace llvm; @@ -800,7 +801,10 @@ void AsmPrinter::EmitConstantValueOnly(const Constant *CV) { O << "(("; EmitConstantValueOnly(Op); APInt ptrMask = APInt::getAllOnesValue(TD->getABITypeSizeInBits(Ty)); - O << ") & " << ptrMask.toStringUnsigned() << ')'; + + SmallString<40> S; + ptrMask.toStringUnsigned(S); + O << ") & " << S.c_str() << ')'; break; } case Instruction::Add: @@ -1058,15 +1062,14 @@ void AsmPrinter::EmitGlobalConstant(const Constant *CV) { printDataDirective(type); EmitConstantValueOnly(CV); if (const ConstantInt *CI = dyn_cast(CV)) { - O << "\t\t\t" - << TAI->getCommentString() - << " 0x" << CI->getValue().toStringUnsigned(16); + SmallString<40> S; + CI->getValue().toStringUnsigned(S, 16); + O << "\t\t\t" << TAI->getCommentString() << " 0x" << S.c_str(); } O << '\n'; } -void -AsmPrinter::EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) { +void AsmPrinter::EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) { // Target doesn't support this yet! abort(); } diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 80dda1f280e..c3728749577 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -4992,7 +4992,7 @@ void SDNode::dump(const SelectionDAG *G) const { } if (const ConstantSDNode *CSDN = dyn_cast(this)) { - cerr << "<" << CSDN->getAPIntValue().toStringUnsigned() << ">"; + cerr << "<" << CSDN->getAPIntValue() << ">"; } else if (const ConstantFPSDNode *CSDN = dyn_cast(this)) { if (&CSDN->getValueAPF().getSemantics()==&APFloat::IEEEsingle) cerr << "<" << CSDN->getValueAPF().convertToFloat() << ">"; diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index a6b7ed37587..b948e8f43ac 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -14,9 +14,8 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/FoldingSet.h" -#include -#include #include "llvm/Support/MathExtras.h" +#include using namespace llvm; diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index d579ae0965b..80747fd12a9 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -15,14 +15,13 @@ #define DEBUG_TYPE "apint" #include "llvm/ADT/APInt.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" -#include +#include #include #include #include -#include - using namespace llvm; /// This enumeration just provides for internal constants used in this @@ -1478,12 +1477,14 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, // is 2^31 so we just set it to -1u. uint64_t b = uint64_t(1) << 32; +#if 0 DEBUG(cerr << "KnuthDiv: m=" << m << " n=" << n << '\n'); DEBUG(cerr << "KnuthDiv: original:"); DEBUG(for (int i = m+n; i >=0; i--) cerr << " " << std::setbase(16) << u[i]); DEBUG(cerr << " by"); DEBUG(for (int i = n; i >0; i--) cerr << " " << std::setbase(16) << v[i-1]); DEBUG(cerr << '\n'); +#endif // D1. [Normalize.] Set d = b / (v[n-1] + 1) and multiply all the digits of // u and v by d. Note that we have taken Knuth's advice here to use a power // of 2 value for d such that d * v[n-1] >= b/2 (b is the base). A power of @@ -1508,11 +1509,13 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, } } u[m+n] = u_carry; +#if 0 DEBUG(cerr << "KnuthDiv: normal:"); DEBUG(for (int i = m+n; i >=0; i--) cerr << " " << std::setbase(16) << u[i]); DEBUG(cerr << " by"); DEBUG(for (int i = n; i >0; i--) cerr << " " << std::setbase(16) << v[i-1]); DEBUG(cerr << '\n'); +#endif // D2. [Initialize j.] Set j to m. This is the loop counter over the places. int j = m; @@ -1636,7 +1639,9 @@ static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, } DEBUG(cerr << '\n'); } +#if 0 DEBUG(cerr << std::setbase(10) << '\n'); +#endif } void APInt::divide(const APInt LHS, uint32_t lhsWords, @@ -2001,114 +2006,112 @@ void APInt::fromString(uint32_t numbits, const char *str, uint32_t slen, } } -std::string APInt::toString(uint8_t radix, bool wantSigned) const { - assert((radix == 10 || radix == 8 || radix == 16 || radix == 2) && +void APInt::toString(SmallVectorImpl &Str, unsigned Radix, + bool Signed) const { + assert((Radix == 10 || Radix == 8 || Radix == 16 || Radix == 2) && "Radix should be 2, 8, 10, or 16!"); - static const char *const digits[] = { - "0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F" - }; - std::string result; - uint32_t bits_used = getActiveBits(); + + // First, check for a zero value and just short circuit the logic below. + if (*this == 0) { + Str.push_back('0'); + return; + } + + static const char Digits[] = "0123456789ABCDEF"; + if (isSingleWord()) { - char buf[65]; - const char *format = (radix == 10 ? (wantSigned ? "%lld" : "%llu") : - (radix == 16 ? "%llX" : (radix == 8 ? "%llo" : 0))); - if (format) { - if (wantSigned) { - int64_t sextVal = (int64_t(VAL) << (APINT_BITS_PER_WORD-BitWidth)) >> - (APINT_BITS_PER_WORD-BitWidth); - sprintf(buf, format, sextVal); - } else - sprintf(buf, format, VAL); + char Buffer[65]; + char *BufPtr = Buffer+65; + + uint64_t N; + if (Signed) { + int64_t I = getSExtValue(); + if (I < 0) { + Str.push_back('-'); + I = -I; + } + N = I; } else { - memset(buf, 0, 65); - uint64_t v = VAL; - while (bits_used) { - uint32_t bit = (uint32_t)v & 1; - bits_used--; - buf[bits_used] = digits[bit][0]; - v >>=1; - } + N = getZExtValue(); } - result = buf; - return result; + + while (N) { + *--BufPtr = Digits[N % Radix]; + N /= Radix; + } + Str.append(BufPtr, Buffer+65); + return; } - if (radix != 10) { - // 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 there value is zero. - - // First, check for a zero value and just short circuit the logic below. - if (*this == 0) - result = "0"; - else { - APInt tmp(*this); - size_t insert_at = 0; - if (wantSigned && this->isNegative()) { - // They want to print the signed version and it is a negative value - // Flip the bits and add one to turn it into the equivalent positive - // value and put a '-' in the result. - tmp.flip(); - tmp++; - result = "-"; - insert_at = 1; - } - // Just shift tmp right for each digit width until it becomes zero - uint32_t shift = (radix == 16 ? 4 : (radix == 8 ? 3 : 1)); - uint64_t mask = radix - 1; - APInt zero(tmp.getBitWidth(), 0); - while (tmp.ne(zero)) { - unsigned digit = - (unsigned)((tmp.isSingleWord() ? tmp.VAL : tmp.pVal[0]) & mask); - result.insert(insert_at, digits[digit]); - tmp = tmp.lshr(shift); - } - } - return result; - } - - APInt tmp(*this); - APInt divisor(4, radix); - APInt zero(tmp.getBitWidth(), 0); - size_t insert_at = 0; - if (wantSigned && tmp[BitWidth-1]) { + APInt Tmp(*this); + + if (Signed && isNegative()) { // They want to print the signed version and it is a negative value // Flip the bits and add one to turn it into the equivalent positive // value and put a '-' in the result. - tmp.flip(); - tmp++; - result = "-"; - insert_at = 1; + Tmp.flip(); + Tmp++; + Str.push_back('-'); } - if (tmp == zero) - result = "0"; - else while (tmp.ne(zero)) { - APInt APdigit(1,0); - APInt tmp2(tmp.getBitWidth(), 0); - divide(tmp, tmp.getNumWords(), divisor, divisor.getNumWords(), &tmp2, - &APdigit); - uint32_t digit = (uint32_t)APdigit.getZExtValue(); - assert(digit < radix && "divide failed"); - result.insert(insert_at,digits[digit]); - tmp = tmp2; + + // We insert the digits backward, then reverse them to get the right order. + unsigned StartDig = Str.size(); + + // 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) { + // 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; + + while (Tmp != 0) { + unsigned Digit = unsigned(Tmp.getRawData()[0]) & MaskAmt; + Str.push_back(Digits[Digit]); + Tmp = Tmp.lshr(ShiftAmt); + } + } else { + APInt divisor(4, 10); + while (Tmp != 0) { + APInt APdigit(1, 0); + APInt tmp2(Tmp.getBitWidth(), 0); + divide(Tmp, Tmp.getNumWords(), divisor, divisor.getNumWords(), &tmp2, + &APdigit); + uint32_t Digit = (uint32_t)APdigit.getZExtValue(); + assert(Digit < Radix && "divide failed"); + Str.push_back(Digits[Digit]); + Tmp = tmp2; + } } - - return result; + + // Reverse the digits before returning. + std::reverse(Str.begin()+StartDig, Str.end()); } -void APInt::dump() const -{ - cerr << "APInt(" << BitWidth << ")=" << std::setbase(16); - if (isSingleWord()) - cerr << VAL; - else for (unsigned i = getNumWords(); i > 0; i--) { - cerr << pVal[i-1] << " "; - } - cerr << " U(" << this->toStringUnsigned(10) << ") S(" - << this->toStringSigned(10) << ")" << std::setbase(10); +/// toString - This returns the APInt as a std::string. Note that this is an +/// inefficient method. It is better to pass in a SmallVector/SmallString +/// to the methods above. +std::string APInt::toString(unsigned Radix = 10, bool Signed = true) const { + SmallString<40> S; + toString(S, Radix, Signed); + return S.c_str(); } + +void APInt::dump() const { + SmallString<40> S, U; + this->toStringUnsigned(U); + this->toStringSigned(S); + fprintf(stderr, "APInt(%db, %su %ss)", BitWidth, U.c_str(), S.c_str()); +} + +void APInt::print(std::ostream &OS, bool isSigned) const { + SmallString<40> S; + this->toString(S, 10, isSigned); + OS << S.c_str(); +} + + // This implements a variety of operations on a representation of // arbitrary precision, two's-complement, bignum integer values. diff --git a/lib/Support/ConstantRange.cpp b/lib/Support/ConstantRange.cpp index 0d22b323502..9c83b7c59de 100644 --- a/lib/Support/ConstantRange.cpp +++ b/lib/Support/ConstantRange.cpp @@ -463,8 +463,7 @@ ConstantRange ConstantRange::truncate(uint32_t DstTySize) const { /// print - Print out the bounds to a stream... /// void ConstantRange::print(std::ostream &OS) const { - OS << "[" << Lower.toStringSigned(10) << "," - << Upper.toStringSigned(10) << ")"; + OS << "[" << Lower << "," << Upper << ")"; } /// dump - Allow printing from a debugger easily... diff --git a/lib/Target/CppBackend/CPPBackend.cpp b/lib/Target/CppBackend/CPPBackend.cpp index 6aa085bc83d..ce86452737d 100644 --- a/lib/Target/CppBackend/CPPBackend.cpp +++ b/lib/Target/CppBackend/CPPBackend.cpp @@ -733,8 +733,8 @@ namespace { } if (const ConstantInt *CI = dyn_cast(CV)) { Out << "ConstantInt* " << constName << " = ConstantInt::get(APInt(" - << cast(CI->getType())->getBitWidth() << ", " - << " \"" << CI->getValue().toStringSigned(10) << "\", 10));"; + << cast(CI->getType())->getBitWidth() << ", \"" + << CI->getValue() << "\", 10));"; } else if (isa(CV)) { Out << "ConstantAggregateZero* " << constName << " = ConstantAggregateZero::get(" << typeName << ");"; diff --git a/lib/Transforms/Utils/LowerSwitch.cpp b/lib/Transforms/Utils/LowerSwitch.cpp index 630f97cd6da..7409e779f80 100644 --- a/lib/Transforms/Utils/LowerSwitch.cpp +++ b/lib/Transforms/Utils/LowerSwitch.cpp @@ -144,11 +144,9 @@ BasicBlock* LowerSwitch::switchConvert(CaseItr Begin, CaseItr End, DOUT << "RHS: " << RHS << "\n"; CaseRange& Pivot = *(Begin + Mid); - DEBUG( DOUT << "Pivot ==> " - << cast(Pivot.Low)->getValue().toStringSigned(10) - << " -" - << cast(Pivot.High)->getValue().toStringSigned(10) - << "\n"); + DEBUG(cerr << "Pivot ==> " + << cast(Pivot.Low)->getValue() << " -" + << cast(Pivot.High)->getValue() << "\n"); BasicBlock* LBranch = switchConvert(LHS.begin(), LHS.end(), Val, OrigBlock, Default); diff --git a/lib/VMCore/AsmWriter.cpp b/lib/VMCore/AsmWriter.cpp index fa512e01711..ad7b5c3ffe3 100644 --- a/lib/VMCore/AsmWriter.cpp +++ b/lib/VMCore/AsmWriter.cpp @@ -507,13 +507,18 @@ static void WriteConstantInt(std::ostream &Out, const Constant *CV, std::map &TypeTable, SlotMachine *Machine) { const int IndentSize = 4; + // FIXME: WHY IS INDENT STATIC?? static std::string Indent = "\n"; if (const ConstantInt *CI = dyn_cast(CV)) { - if (CI->getType() == Type::Int1Ty) + if (CI->getType() == Type::Int1Ty) { Out << (CI->getZExtValue() ? "true" : "false"); - else - Out << CI->getValue().toStringSigned(10); - } else if (const ConstantFP *CFP = dyn_cast(CV)) { + return; + } + Out << CI->getValue(); + return; + } + + if (const ConstantFP *CFP = dyn_cast(CV)) { if (&CFP->getValueAPF().getSemantics() == &APFloat::IEEEdouble || &CFP->getValueAPF().getSemantics() == &APFloat::IEEEsingle) { // We would like to output the FP constant value in exponential notation, @@ -522,8 +527,8 @@ static void WriteConstantInt(std::ostream &Out, const Constant *CV, // the value back and get the same value. // bool isDouble = &CFP->getValueAPF().getSemantics()==&APFloat::IEEEdouble; - double Val = (isDouble) ? CFP->getValueAPF().convertToDouble() : - CFP->getValueAPF().convertToFloat(); + double Val = isDouble ? CFP->getValueAPF().convertToDouble() : + CFP->getValueAPF().convertToFloat(); std::string StrVal = ftostr(CFP->getValueAPF()); // Check to make sure that the stringized number is not some string like @@ -1054,7 +1059,7 @@ void AssemblyWriter::printAlias(const GlobalAlias *GA) { printType(F->getFunctionType()); Out << "* "; - if (!F->hasName()) + if (F->hasName()) PrintLLVMName(Out, F); else Out << "@\"\"";