[PATCH] PR libstdc++/13045 / C++ demangler, floating values and function pointer type return type postfix fix.
Carlo Wood
carlo@alinoe.com
Mon Nov 24 01:20:00 GMT 2003
2003-11-24 Carlo Wood <carlo@alinoe.com>
PR libstdc++/13045
* bits/demangle.h
namespace __gnu_cxx::demangler
(enum substitution_nt): Removed trailing comma.
(print_IEEE_fp): Added extern declaration.
(session<Allocator>::decode_real): Added.
(session<Allocator>::decode_literal): Call decode_real for
float and double literals.
(session<Allocator>::decode_type_with_postfix): Put the postfix
of the return type of (member) functions after the function
instead of after the return type. Also, put a space after the
prefix of qualified function pointers: "int (* const<space>".
* src/demangle.cc: include most dependent header file first.
namespace <anonymous>
(struct decimal_float_data): Added.
(class decimal_float): Added.
(int const m1023, int const m1, int const m0, int const p1): Added.
(decimal_float_data const constants[]): Added.
namespace __gnu_cxx::demangler
(print_IEEE_fp): Added.
* testsuite/demangle/regression/cw-16.cc: Updated one
and added three tests.
OK?
--
Carlo Wood <carlo@alinoe.com>
-------------- next part --------------
Index: libstdc++-v3/include/bits/demangle.h
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/include/bits/demangle.h,v
retrieving revision 1.11
diff -u -d -p -r1.11 demangle.h
--- libstdc++-v3/include/bits/demangle.h 12 Nov 2003 02:18:36 -0000 1.11
+++ libstdc++-v3/include/bits/demangle.h 23 Nov 2003 14:31:18 -0000
@@ -91,7 +91,7 @@ namespace __gnu_cxx
template_template_param,
nested_name_prefix,
nested_name_template_prefix,
- unscoped_template_name,
+ unscoped_template_name
};
struct substitution_st
@@ -408,6 +408,7 @@ namespace __gnu_cxx
bool decode_class_enum_type(string_type& output);
bool decode_expression(string_type& output);
bool decode_literal(string_type& output);
+ template<typename FloatType> bool decode_real(string_type& output);
bool decode_local_name(string_type& output);
bool decode_name(string_type& output,
string_type& nested_name_qualifiers);
@@ -879,6 +880,71 @@ namespace __gnu_cxx
_GLIBCXX_DEMANGLER_RETURN;
}
+ extern void print_IEEE_fp(char* buf, unsigned long* words,
+ int nbits_exponent, int nbits_fraction, int precision);
+
+ template<typename Allocator>
+ template<typename FloatType>
+ bool
+ session<Allocator>::decode_real(string_type& output)
+ {
+ _GLIBCXX_DEMANGLER_DOUT_ENTERING("decode_real<" <<
+ type_info_of<FloatType>().demangled_name() << '>');
+
+ if (sizeof(FloatType) != 4 && sizeof(FloatType) != 8)
+ {
+ // Don't fail - just print out the literal string in hex.
+ output += '[';
+ char c = current();
+ for(size_t nibble_cnt = 0; nibble_cnt < 2 * sizeof(FloatType); ++nibble_cnt)
+ {
+ if (c < '0' || c > 'f' || (c > '9' && c < 'a'))
+ _GLIBCXX_DEMANGLER_FAILURE;
+ output += c;
+ c = next();
+ }
+ output += ']';
+ _GLIBCXX_DEMANGLER_RETURN;
+ }
+
+ unsigned long words[sizeof(FloatType) / 4]; // 32 bit per long.
+ unsigned long* word = &words[0];
+
+ // The following assumes that leading zeroes are also included
+ // in the mangled name (which is what g++ does), I am not sure
+ // that is conforming to the standard though.
+ unsigned char nibble, c = current();
+ for(size_t word_cnt = sizeof(FloatType) / 4; word_cnt > 0; --word_cnt)
+ {
+ for (int nibble_cnt = 0; nibble_cnt < 8; ++nibble_cnt)
+ {
+ // Translate character into nibble.
+ if (c < '0' || c > 'f')
+ _GLIBCXX_DEMANGLER_FAILURE;
+ if (c <= '9')
+ nibble = c - '0';
+ else if (c >= 'a')
+ nibble = c - 'a' + 10;
+ else
+ _GLIBCXX_DEMANGLER_FAILURE;
+ // Write nibble into word array.
+ if (nibble_cnt == 0)
+ *word = nibble << 28;
+ else
+ *word |= (nibble << (28 - 4 * nibble_cnt));
+ c = next();
+ }
+ ++word;
+ }
+ char buf[24];
+ if (sizeof(FloatType) == 8)
+ print_IEEE_fp(buf, words, 11, 52, 17);
+ else
+ print_IEEE_fp(buf, words, 8, 23, 8);
+ output += buf;
+ _GLIBCXX_DEMANGLER_RETURN;
+ }
+
template<typename Allocator>
bool
session<Allocator>::decode_literal(string_type& output)
@@ -925,7 +991,17 @@ namespace __gnu_cxx
_GLIBCXX_DEMANGLER_FAILURE;
output += ')';
}
- if (!decode_number(output))
+ if (c == 'd')
+ {
+ if (!decode_real<double>(output))
+ _GLIBCXX_DEMANGLER_FAILURE;
+ }
+ else if (c == 'f')
+ {
+ if (!decode_real<float>(output))
+ _GLIBCXX_DEMANGLER_FAILURE;
+ }
+ else if (!decode_number(output))
_GLIBCXX_DEMANGLER_FAILURE;
#ifdef _GLIBCXX_DEMANGLER_STYLE_LITERAL
if (c == 'j' || c == 'm' || c == 'y')
@@ -1508,8 +1584,8 @@ namespace __gnu_cxx
// <Q>F<R><B>E ==> R (Q)B "<R>", "<B>" (<B> recursive)
// and "F<R><B>E".
//
- // Note that if <R> has postfix qualifiers (an array), then those
- // are added AFTER the (member) function type. For example:
+ // Note that if <R> has postfix qualifiers (an array or function), then
+ // those are added AFTER the (member) function type. For example:
// <Q>FPA<R><B>E ==> R (*(Q)B) [], where the PA added the prefix
// "(*" and the postfix ") []".
//
@@ -1863,7 +1939,8 @@ namespace __gnu_cxx
// Return type.
// Constructors, destructors and conversion operators don't
// have a return type, but seem to never get here.
- if (!decode_type_with_postfix(prefix, postfix))
+ string_type return_type_postfix;
+ if (!decode_type_with_postfix(prefix, return_type_postfix))
// substitution: <R> recursive
{
failure = true;
@@ -1885,9 +1962,10 @@ namespace __gnu_cxx
add_substitution(start_pos, type);
// substitution: all qualified types if any.
qualifiers->decode_qualifiers(prefix, postfix);
- prefix += ")";
- prefix += bare_function_type;
- prefix += member_function_qualifiers;
+ postfix += ")";
+ postfix += bare_function_type;
+ postfix += member_function_qualifiers;
+ postfix += return_type_postfix;
goto decode_type_exit;
}
qualifiers->add_qualifier_start(pointer_to_member, start_pos,
@@ -1929,17 +2007,19 @@ namespace __gnu_cxx
// substitution: "<R>", "<B>" (<B> recursive) and "F<R><B>E".
// Return type.
- if (!decode_type_with_postfix(prefix, postfix))
+ string_type return_type_postfix;
+ if (!decode_type_with_postfix(prefix, return_type_postfix))
// Substitution: "<R>".
{
failure = true;
break;
}
- // Only array (pointer) types have a postfix.
- // In that case we don't want the space but
- // expect something like prefix is "int (*"
- // and postfix is ") [1]".
- if (postfix.size() == 0)
+ // Only array and function (pointer) types have a postfix.
+ // In that case we don't want the space but expect something
+ // like prefix is "int (*" and postfix is ") [1]".
+ // We do want the space if this pointer is qualified.
+ if (return_type_postfix.size() == 0 ||
+ (prefix.size() > 0 && *prefix.rbegin() != '*'))
prefix += ' ';
prefix += '(';
string_type bare_function_type;
@@ -1953,10 +2033,11 @@ namespace __gnu_cxx
add_substitution(start_pos, type); // Substitution: "F<R><B>E".
qualifiers->decode_qualifiers(prefix, postfix);
// substitution: all qualified types, if any.
- prefix += ")";
+ postfix += ")";
if (extern_C)
- prefix += " [extern \"C\"] ";
- prefix += bare_function_type;
+ postfix += " [extern \"C\"] ";
+ postfix += bare_function_type;
+ postfix += return_type_postfix;
break;
}
case 'T':
Index: libstdc++-v3/src/demangle.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/src/demangle.cc,v
retrieving revision 1.3
diff -u -d -p -r1.3 demangle.cc
--- libstdc++-v3/src/demangle.cc 2 Oct 2003 14:29:26 -0000 1.3
+++ libstdc++-v3/src/demangle.cc 23 Nov 2003 14:31:26 -0000
@@ -28,8 +28,8 @@
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
-#include <cxxabi.h>
#include <bits/demangle.h>
+#include <cxxabi.h>
// __cxa_demangle
//
@@ -164,4 +164,558 @@ namespace __cxxabiv1
}
return finish(result.data(), result.size(), buf, n, status);
}
+
} // namespace __cxxabiv1
+
+namespace
+{
+
+// class decimal_float
+//
+// This internal class represents a floating point value
+// with a precision of `mantissa_size_c' * 4 digits.
+// With `mantissa_size_c' set to 5 that gives 20 digits,
+// being more than 66 bits. However, due to round off
+// errors, the last `size of binary exponent' bits are
+// unreliable.
+//
+// For IEEE double precision, the size of the exponent
+// is 11 bits and thus is this class only accurate in
+// 55 bits. Therefore, only 17 digits may be printed
+// in that case. This size is precisely significant for
+// the 52 bits of precision in the IEEE format as well.
+//
+// For IEEE single precision, the size of the exponent
+// is 8 bits and we will have 58 bits of precision. It
+// makes no sense to print more than 7 digits in that
+// case because IEEE single precision has only 23 bits
+// of precision by itself.
+//
+// The internal value of a `decimal_float' object is
+//
+// ( mantissa[0] +
+// 10000 * mantissa[1] +
+// 10000**2 * mantissa[2] +
+// 10000**3 * mantissa[3] +
+// 10000**4 * mantissa[4] ) * 10**exponent
+//
+// The member `max_precision_reached' is set to true
+// when the value of the object cannot be multiplied
+// with 10 anymore without changing the exponent,
+// in other words, when mantissa[4] >= 1000.
+// Its value is fuzzy however and only influences
+// the maximum achievable accuracy.
+
+static int const mantissa_size_c = 5;
+
+struct decimal_float_data {
+ unsigned long mantissa[mantissa_size_c];
+ int exponent;
+ bool max_precision_reached;
+};
+
+class decimal_float {
+private:
+ decimal_float_data M_data;
+
+private:
+ void M_do_overflow(unsigned long prev_borrow);
+ void M_do_carry(void);
+
+public:
+ void set_2pow2pow(int power);
+ void set_2pow(int power);
+ void set_expstart(int expsize);
+ void set_zero(void);
+ void divide_by_two(bool decrement_exponent);
+ bool decrement_exponent(void);
+ decimal_float& operator+=(decimal_float const& term);
+ decimal_float& operator*=(decimal_float const& factor);
+ void print_to_with_precision(char* buf, int precision) const;
+};
+
+// These names must match the corresponding index of the table below
+// and the p* constants must be contigious and in the given order.
+// Same for the constants m1023 ... m15.
+// Name Table-index
+int const m1023 = 0; // Corresponds with an exponent of 11 bits.
+#if 0
+int const m511 = 1;
+int const m255 = 2;
+int const m127 = 3; // Corresponds with an exponent of 8 bits.
+int const m63 = 4;
+int const m31 = 5;
+int const m15 = 6;
+#endif
+int const m1 = 7;
+int const m0 = 8; // Must have the same exponent as m1.
+int const p1 = 9;
+#if 0
+int const p2 = 10;
+int const p4 = 11;
+int const p8 = 12;
+int const p16 = 13;
+int const p32 = 14;
+int const p64 = 15;
+int const p128 = 16;
+int const p256 = 17;
+int const p512 = 18;
+int const p1024 = 19;
+#endif
+
+decimal_float_data const constants[] = {
+ { 6915, 3600, 2925, 5369, 1112, -327, true }, // m1023; 2 ** -1023
+ { 3487, 41, 4624, 6681, 1491, -173, true }, // m511; 2 ** -511
+ { 9251, 8888, 1101, 2337, 1727, -96, true }, // m255; 2 ** -255
+ { 5398, 1437, 5411, 4717, 5877, -58, true }, // m127; 2 ** -127
+ { 4340, 5504, 7248, 2021, 1084, -38, true }, // m63; 2 ** -63
+ { 5781, 7392, 7307, 6128, 4656, -29, true }, // m31; 2 ** -31
+ { 0, 0, 1250, 7578, 3051, -24, true }, // m15; 2 ** -15
+ { 5, 0, 0, 0, 0, -1, false }, // m1; 2 ** -1
+ { 10, 0, 0, 0, 0, -1, false }, // m0; 2 ** 0
+ { 2, 0, 0, 0, 0, 0, false }, // p1; 2 ** 1
+ { 4, 0, 0, 0, 0, 0, false }, // p2; 2 ** 2
+ { 16, 0, 0, 0, 0, 0, false }, // p4; 2 ** 4
+ { 256, 0, 0, 0, 0, 0, false }, // p8; 2 ** 8
+ { 5536, 6, 0, 0, 0, 0, false }, // p16; 2 ** 16
+ { 7296, 9496, 42, 0, 0, 0, false }, // p32; 2 ** 32
+ { 1616, 955, 737, 6744, 1844, 0, true }, // p64; 2 ** 64
+ { 6346, 9384, 6920, 8236, 3402, 19, true }, // p128; 2 ** 128
+ { 9542, 3161, 9237, 9208, 1157, 58, true }, // p256; 2 ** 256
+ { 7100, 4259, 9299, 7807, 1340, 135, true }, // p512; 2 ** 512
+ { 9077, 2315, 3486, 6931, 1797, 289, true }, // p1024; 2 ** 1024
+};
+
+// Handle access digits in the most significant
+// element of the mantissa array.
+void decimal_float::M_do_overflow(unsigned long prev_borrow)
+{
+ // assert(M_data.mantissa[mantissa_size_c - 1] > 9999);
+
+ // Even after shifting the access digits right,
+ // M_data.mantissa[mantissa_size_c - 1] will still be
+ // larger than 999.
+ M_data.max_precision_reached = true;
+
+ // Count the access digits and update the exponent
+ // already in order to keep the value constant.
+ unsigned long divider = 10;
+ ++M_data.exponent;
+ while (prev_borrow >= divider)
+ {
+ divider *= 10;
+ ++M_data.exponent;
+ }
+
+ // Finally, shift the value in the mantissa a few
+ // digits to the right. Round off what falls off.
+ unsigned long multiplier = 10000 / divider;
+ for (int i = mantissa_size_c - 1; i >= 0; --i)
+ {
+ unsigned long borrow = M_data.mantissa[i] % divider;
+ if (i == 0)
+ M_data.mantissa[i] += divider / 2; // Round off.
+ M_data.mantissa[i] /= divider;
+ M_data.mantissa[i] += prev_borrow * multiplier;
+ prev_borrow = borrow;
+ }
+}
+
+// Handle access digits in the elements of the mantissa array.
+void decimal_float::M_do_carry(void)
+{
+ for (int i = 0; i < mantissa_size_c - 1; ++i)
+ {
+ if (M_data.mantissa[i] >= 10000)
+ {
+ M_data.mantissa[i + 1] += M_data.mantissa[i] / 10000;
+ M_data.mantissa[i] %= 10000;
+ }
+ }
+ if (M_data.mantissa[mantissa_size_c - 1] >= 10000)
+ M_do_overflow(0);
+}
+
+// Initialize the object to a value of 2 ** (2 ** power).
+inline void decimal_float::set_2pow2pow(int power)
+{
+ // assert(0 <= power && power <= 10);
+ std::memcpy(&M_data, &constants[p1 + power], sizeof(decimal_float_data));
+}
+
+// Initialize the object to a value of 2 ** power.
+inline void decimal_float::set_2pow(int power)
+{
+ // assert(power == 0 || power == 1);
+ std::memcpy(&M_data, &constants[power], sizeof(decimal_float_data));
+}
+
+// Initialize the object to a value of 2 ** (1 - (2 ** (expsize - 1))).
+inline void decimal_float::set_expstart(int expsize)
+{
+ // assert(expsize <= 11 && expsize >= 5);
+ std::memcpy(&M_data, &constants[m1023 + 11 - expsize],
+ sizeof(decimal_float_data));
+}
+
+// Initialize the object to zero. Must have the same exponent as m0.
+inline void decimal_float::set_zero(void)
+{
+ std::memcpy(&M_data, &constants[m0], sizeof(decimal_float_data));
+ M_data.mantissa[0] = 0;
+}
+
+// Divide the value of this object by two in one of two possible ways:
+// If `decrement_exponent' is true - then decrement the exponent by
+// one and multiply the mantissa with five. Otherwise just divide
+// the mantissa by two.
+void decimal_float::divide_by_two(bool decrement_exponent)
+{
+ if (decrement_exponent)
+ {
+ for (int i = 0; i < mantissa_size_c; ++i)
+ M_data.mantissa[i] *= 5;
+ M_do_carry();
+ --M_data.exponent;
+ }
+ else
+ {
+ unsigned long prev_borrow = M_data.mantissa[mantissa_size_c - 1] % 2;
+ if ((M_data.mantissa[mantissa_size_c - 1] /= 2) < 1000)
+ M_data.max_precision_reached = false;
+ for (int i = mantissa_size_c - 2; i >= 0; --i)
+ {
+ unsigned long borrow = M_data.mantissa[i] % 2;
+ M_data.mantissa[i] /= 2;
+ M_data.mantissa[i] += prev_borrow * 5000;
+ prev_borrow = borrow;
+ }
+ if (prev_borrow)
+ {
+ // Round off.
+ if (++M_data.mantissa[0] == 10000)
+ M_do_carry();
+ }
+ }
+}
+
+// If possible, multiply the mantissa with 10 and
+// decrement the exponent with one. This is used
+// to keep the exponent of this object equal to
+// another object that is being divided by two.
+bool decimal_float::decrement_exponent(void)
+{
+ if (M_data.max_precision_reached)
+ return false;
+ for (int i = 0; i < mantissa_size_c; ++i)
+ M_data.mantissa[i] *= 10;
+ M_do_carry();
+ if (M_data.mantissa[mantissa_size_c - 1] >= 1000)
+ M_data.max_precision_reached = true;
+ --M_data.exponent;
+ return true;
+}
+
+// Add two decimal_floats that have the same exponent.
+decimal_float& decimal_float::operator+=(decimal_float const& term)
+{
+ // assert(M_data.exponent == term.M_data.exponent);
+ for (int i = 0; i < mantissa_size_c; ++i)
+ M_data.mantissa[i] += term.M_data.mantissa[i];
+ M_do_carry();
+ return *this;
+}
+
+// The real work. Multiply this object with `factor'.
+decimal_float& decimal_float::operator*=(decimal_float const& factor)
+{
+ // Count the number of most-significant mantissa elements (digits)
+ // that contain zero (of either factor), but stop counting if we reach
+ // mantissa_size_c - 1.
+ int zero_digits = 0;
+ while (M_data.mantissa[mantissa_size_c - 1 - zero_digits] == 0)
+ if (++zero_digits == mantissa_size_c - 1)
+ break;
+ if (zero_digits < mantissa_size_c - 1)
+ {
+ int offset = mantissa_size_c - 1 + zero_digits;
+ while (factor.M_data.mantissa[offset - zero_digits] == 0)
+ if (++zero_digits == mantissa_size_c - 1)
+ break;
+ }
+
+ // Set `this_mantissa' to point to the mantissa of this object;
+ // make a copy only when we would overwrite its values when
+ // still needed below.
+ unsigned long tmp_mantissa[mantissa_size_c];
+ unsigned long* this_mantissa;
+ if (zero_digits == 0)
+ this_mantissa = M_data.mantissa;
+ else
+ {
+ std::memcpy(tmp_mantissa, M_data.mantissa, sizeof(tmp_mantissa));
+ this_mantissa = tmp_mantissa;
+ }
+
+ // Set lss (least significant (loop) size, but don't ask me why it is
+ // called that way - it gets a bit complicated here) to, heh, what works.
+ int lss = mantissa_size_c - 1 - zero_digits;
+ // Now hold your breath...
+ M_data.exponent += factor.M_data.exponent + 4 * lss;
+ unsigned long sum = 0;
+ for (int i = 0; i < lss; ++i)
+ sum += this_mantissa[i] * factor.M_data.mantissa[lss - 1 - i];
+ sum += 5000; // Round off.
+ sum /= 10000;
+ for (int j = 0; j < mantissa_size_c; ++j)
+ {
+ int loop_bgn = std::max(0, lss + j - (mantissa_size_c - 1));
+ int loop_end = std::min(mantissa_size_c - 1, lss + j);
+ for (int i = loop_bgn; i <= loop_end; ++i)
+ sum += this_mantissa[i] * factor.M_data.mantissa[lss + j - i];
+ M_data.mantissa[j] = sum;
+ sum /= 10000;
+ M_data.mantissa[j] -= 10000 * sum;
+ }
+ // ... ahhh. Ok. And do overflow management when needed.
+ if (sum > 0)
+ M_do_overflow(sum);
+}
+
+// Print to `buf', writes: "<digit>.<digits>e<sign><exponent>\0".
+// sizeof(buf) must be at least 7 larger than `precision':
+// strlen(<digit><digits>) <= precision.
+// strlen(.e<sign><exponent>) == 6, plus one for the trailing '\0'.
+void decimal_float::print_to_with_precision(char* buf, int precision) const
+{
+ // First do the round off.
+ decimal_float tmp(*this);
+ if (!M_data.max_precision_reached)
+ {
+ // In this case we are probably exact, so we
+ // don't really need to round off. Because leading
+ // zeroes are not printed, add number of leading 0's
+ // to `precision'.
+ for (int i = mantissa_size_c - 1; i >= 0; --i)
+ for(int shift = 1000; shift; shift /= 10)
+ {
+ if (M_data.mantissa[i] >= shift)
+ {
+ i = 0;
+ break;
+ }
+ ++precision;
+ }
+ }
+ int e = 4 * mantissa_size_c - 1;
+ if (precision < mantissa_size_c * 4)
+ {
+ int cut = e - precision;
+ int cuti = cut / 4;
+ int cutr = cut % 4;
+ unsigned long shift = 10;
+ while(cutr--)
+ shift *= 10;
+ tmp.M_data.mantissa[cuti] += shift / 2; // Round off.
+ if (tmp.M_data.mantissa[cuti] >= 10000)
+ tmp.M_do_carry();
+ }
+
+ bool leading = true;
+ char* p = buf;
+ int tz = 0;
+ for (int i = mantissa_size_c - 1; i >= 0 && precision; --i)
+ {
+ unsigned long digit = tmp.M_data.mantissa[i];
+ for(int shift = 1000; shift; shift /= 10)
+ {
+ int d = digit / shift;
+ digit -= d * shift;
+ if (leading && d != 0)
+ leading = false;
+ if (leading) // Suppress leading zeroes.
+ --e;
+ else
+ {
+ if (d == 0) // Suppress and count trailing zeroes.
+ ++tz;
+ else
+ {
+ if (p == buf + 1)
+ *p++ = '.';
+ while(tz--)
+ *p++ = '0';
+ *p++ = d + '0';
+ tz = 0;
+ }
+ if (--precision == 0)
+ break;
+ }
+ }
+ }
+ e += tmp.M_data.exponent;
+ if (e != 0)
+ {
+ *p++ = 'e';
+ if (e > 0)
+ *p++ = '+';
+ else
+ {
+ *p++ = '-';
+ e = -e;
+ }
+ int shift = 100;
+ leading = true;
+ while(shift)
+ {
+ int d = e / shift;
+ e -= d * shift;
+ if (leading && d != 0)
+ leading = false;
+ if (!leading)
+ *p++ = '0' + d;
+ shift /= 10;
+ }
+ }
+ *p = 0;
+}
+
+} // namespace
+
+namespace __gnu_cxx
+{
+ namespace demangler
+ {
+
+// Important note:
+// Please realize that this function, and thus the class decimal_float above,
+// do NOT allocate ANY memory. Therefore it does not need Allocator and
+// therefore we can put it here instead of in bits/demangle.h but that
+// doesn't mean we can start to allocate memory through malloc(), or call
+// system library calls that might do so, like sprintf(.."%e"..) would do!.
+//
+// It is an important feature of the bits/demangler.h API that it never
+// allocates any memory except through the Allocator class.
+
+
+// External interface (used by bits/demangle.h):
+
+// print_IEEE_fp(buf, words, nbits_exponent, nbits_fraction, precision)
+//
+// buf : Output buffer, the result is written to this buffer
+// and terminated with a trailing '\0'. The size of
+// this buffer must be at least `precision + 7'.
+// words : A pointer to an array with unsigned integers. Only
+// the 32 least significant bits of each element are
+// used. The first element contains the word with the
+// most significant bits. Bit 31 in each element
+// represents the most significant bit of that 32-bit
+// word. See the description of IEEE 754-1985 for
+// the exact meaning. Basically they mean:
+// SEEEEEEEEMMMMMMMMMMMMMMMMMMMM, where S is the sign
+// bit, EEEEEEEE the exponent and MMMMMMMMMMMMMMMMMMMM
+// the mantissa.
+// nbits_exponent : The number of bits in `sign_and_exponent' that
+// represent the exponent.
+// nbits_fraction : The total number of bits in `fraction', a value
+// larger than 52 will result in inaccurate output.
+// precision : The maximum number of digits in the mantissa
+// (including the first digit before the dot) that
+// will be written to `buf'. This precision should
+// correspond to the accuracy given by `nbits_fraction'
+// of course.
+
+void print_IEEE_fp(char* buf, unsigned long* words,
+ int nbits_exponent, int nbits_fraction, int precision)
+{
+ // This function was written using
+ // http://www.psc.edu/general/software/packages/ieee/ieee.html
+ // as reference for the IEEE 754-1985 standard.
+
+ // assert( nbits_fraction <= 52 && nbits_exponent <= 11 &&
+ // nbits_exponent >= 5 && precision <= 17 );
+ unsigned long sign_mask = 1 << nbits_exponent;
+ unsigned long exponent_mask = sign_mask - 1;
+ unsigned long sign_and_exponent = words[0] >> (31 - nbits_exponent);
+ unsigned long exponent = sign_and_exponent & exponent_mask;
+ int nelem_fraction = (nbits_fraction + nbits_exponent) / 32 + 1;
+ unsigned long mask_first_elem = 0xffffffffUL >> (nbits_exponent + 1);
+ unsigned long mask_last_elem = ~((1UL << (nelem_fraction * 32 -
+ nbits_fraction - nbits_exponent - 1)) - 1);
+ unsigned long fraction_nonzero = (words[0] & mask_first_elem);
+ if (nelem_fraction == 1)
+ fraction_nonzero &= mask_last_elem;
+ else
+ {
+ fraction_nonzero |= (words[nelem_fraction - 1] & mask_last_elem);
+ for (int i = 1; i < nelem_fraction - 1; ++i)
+ fraction_nonzero |= words[i];
+ }
+ if (exponent == exponent_mask && fraction_nonzero)
+ {
+ strcpy(buf, "nan");
+ return;
+ }
+ if ((sign_and_exponent & sign_mask))
+ *buf++ = '-';
+ if (exponent == exponent_mask && !fraction_nonzero)
+ {
+ strcpy(buf, "inf");
+ return;
+ }
+ bool normalized = true;
+ if (exponent == 0)
+ {
+ if (!fraction_nonzero)
+ {
+ strcpy(buf, "0");
+ return;
+ }
+ else
+ {
+ normalized = false;
+ exponent = 1;
+ }
+ }
+
+ decimal_float result;
+ if (normalized)
+ result.set_2pow(m0); // 1.0 ; The 1 in (1.F)
+ else
+ result.set_zero(); // 0.0 ; The 0 in (0.F)
+ decimal_float bit;
+ bit.set_2pow(m1); // 0.5 ; 2 ** (-bit_cnt - 1)
+ unsigned long mask = 0x40000000 >> nbits_exponent;
+ for (int bit_cnt = 0; bit_cnt < nbits_fraction; ++bit_cnt)
+ {
+ if ((*words & mask))
+ result += bit;
+ bool success = result.decrement_exponent();
+ bit.divide_by_two(success); // Keep exponents equal for easy addition.
+ if (!(mask >>= 1))
+ {
+ mask = 0x80000000;
+ ++words;
+ }
+ }
+ decimal_float two_pow_exponent;
+ two_pow_exponent.set_expstart(nbits_exponent);
+ // 2 ** (1 - 2 ** (nbits_exponent - 1)),
+ // where 1 - 2 ** (nbits_exponent - 1) is
+ // the two's-complement exponent 'offset'.
+ mask = 1 << (nbits_exponent - 1);
+ for (int bit_cnt = nbits_exponent - 1; bit_cnt >= 0; --bit_cnt)
+ {
+ if ((exponent & mask))
+ {
+ bit.set_2pow2pow(bit_cnt); // 2 ** (2 ** bit_cnt)
+ two_pow_exponent *= bit;
+ }
+ mask >>= 1;
+ }
+ result *= two_pow_exponent;
+ result.print_to_with_precision(buf, precision);
+}
+
+ } // namespace demangler
+} // namespace __gnu_cxx
Index: libstdc++-v3/testsuite/demangle/regression/cw-16.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/testsuite/demangle/regression/cw-16.cc,v
retrieving revision 1.3
diff -u -d -p -r1.3 cw-16.cc
--- libstdc++-v3/testsuite/demangle/regression/cw-16.cc 12 Nov 2003 02:18:37 -0000 1.3
+++ libstdc++-v3/testsuite/demangle/regression/cw-16.cc 23 Nov 2003 14:31:31 -0000
@@ -36,11 +36,18 @@ verify_demangle("_Z1fILi5E1AEvN1CIXqugtT
verify_demangle("_Z1fILi5EEvN1AIXcvimlT_Li22EEE1qE",
"void f<5>(A<(int)((5) * (22))>::q)");
verify_demangle("_Z1fPFYPFiiEiE",
- "f(int (*)(int) (*) [extern \"C\"] (int))");
+ "f(int (*(*) [extern \"C\"] (int))(int))");
verify_demangle("_Z1fI1XENT_1tES2_",
"X::t f<X>(X::t)");
verify_demangle("_Z1fILi5E1AEvN1CIXstN1T1tEEXszsrS2_1tEE1qE",
"void f<5, A>(C<sizeof (T::t), sizeof (T::t)>::q)");
+// 2003/11/22, libstdc++/13045
+verify_demangle("_Z1fILi1ELc120EEv1AIXplT_cviLd4028ae147ae147aeEEE",
+ "void f<1, (char)120>(A<(1) + ((int)((double)1.234e+1))>)");
+verify_demangle("_Z1fILi1ELc120EEv1AIXplT_cviLf3f800000EEE",
+ "void f<1, (char)120>(A<(1) + ((int)((float)1))>)");
+verify_demangle("_Z9hairyfuncM1YKFPVPFrPA2_PM1XKFKPA3_ilEPcEiE",
+ "hairyfunc(int (* const (X::** (* restrict (* volatile* (Y::*)(int) const)(char*)) [2])(long) const) [3])");
return 0;
}
More information about the Libstdc++
mailing list