This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] libstdc++/88111 and libstdc++/88113 fix src/c++17/memory_resource.cc for 16-bit targets


Two patches to fix the build on msp430-elf which has 16-bit or 20-bit
pointers.

The patch for 88111 also affects other targets, by changing the
default values that are used when pool_options members are zero. The
new default values depend on the number of bits in size_t.

Bootstrapped on msp430-elf, tested on powerpc64le-linux.

commit b5ba0a7b875c3524d447452531416eabf218e6e9
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Nov 21 18:16:45 2018 +0000

    PR libstdc++/88111 Make maximum block size depend on size_t width
    
            PR libstdc++/88111
            * include/std/memory_resource (pool_options): Add Doxygen comments.
            * src/c++17/memory_resource.cc (pool_sizes): Only use suitable values
            on targets with 16-bit or 20-bit size_t type.
            (munge_options): Make default values depend on width of size_t type.

diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource
index 87ad25d60f3..e9a46a3b455 100644
--- a/libstdc++-v3/include/std/memory_resource
+++ b/libstdc++-v3/include/std/memory_resource
@@ -299,13 +299,25 @@ namespace pmr
     { return !(__a == __b); }
 
 
+  /// Parameters for tuning a pool resource's behaviour.
   struct pool_options
   {
+    /** @brief Upper limit on number of blocks in a chunk.
+     *
+     * A lower value prevents allocating huge chunks that could remain mostly
+     * unused, but means pools will need to replenished more frequently.
+     */
     size_t max_blocks_per_chunk = 0;
+
+    /* @brief Largest block size (in bytes) that should be served from pools.
+     *
+     * Larger allocations will be served directly by the upstream resource,
+     * not from one of the pools managed by the pool resource.
+     */
     size_t largest_required_pool_block = 0;
   };
 
-  // Common implementation details for unsynchronized/synchronized pool resources.
+  // Common implementation details for un-/synchronized pool resources.
   class __pool_resource
   {
     friend class synchronized_pool_resource;
diff --git a/libstdc++-v3/src/c++17/memory_resource.cc b/libstdc++-v3/src/c++17/memory_resource.cc
index 6198e6b68ca..929df93233c 100644
--- a/libstdc++-v3/src/c++17/memory_resource.cc
+++ b/libstdc++-v3/src/c++17/memory_resource.cc
@@ -825,10 +825,15 @@ namespace pmr
       128, 192,
       256, 320, 384, 448,
       512, 768,
+#if __SIZE_WIDTH__ > 16
       1024, 1536,
       2048, 3072,
-      1<<12, 1<<13, 1<<14, 1<<15, 1<<16, 1<<17,
+#if __SIZE_WIDTH__ > 20
+      1<<12, 1<<13, 1<<14,
+      1<<15, 1<<16, 1<<17,
       1<<20, 1<<21, 1<<22 // 4MB should be enough for anybody
+#endif
+#endif
   };
 
   pool_options
@@ -839,10 +844,13 @@ namespace pmr
     // replaced with implementation-defined defaults, and sizes may be
     // rounded to unspecified granularity.
 
-    // Absolute maximum. Each pool might have a smaller maximum.
+    // max_blocks_per_chunk sets the absolute maximum for the pool resource.
+    // Each pool might have a smaller maximum, because pools for very large
+    // objects might impose  smaller limit.
     if (opts.max_blocks_per_chunk == 0)
       {
-	opts.max_blocks_per_chunk = 1024 * 10; // TODO a good default?
+	// Pick a default that depends on the number of bits in size_t.
+	opts.max_blocks_per_chunk = __SIZE_WIDTH__ << 8;
       }
     else
       {
@@ -854,10 +862,15 @@ namespace pmr
 	opts.max_blocks_per_chunk = chunk::max_blocks_per_chunk();
       }
 
-    // Absolute minimum. Likely to be much larger in practice.
+    // largest_required_pool_block specifies the largest block size that will
+    // be allocated from a pool. Larger allocations will come directly from
+    // the upstream resource and so will not be pooled.
     if (opts.largest_required_pool_block == 0)
       {
-	opts.largest_required_pool_block = 4096; // TODO a good default?
+	// Pick a sensible default that depends on the number of bits in size_t
+	// (pools with larger block sizes must be explicitly requested by
+	// using a non-zero value for largest_required_pool_block).
+	opts.largest_required_pool_block = __SIZE_WIDTH__ << 6;
       }
     else
       {

commit 14974318adc5e9d56e827cdfa39207e7c7be9e6d
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Nov 21 17:39:51 2018 +0000

    PR libstdc++/88113 use size_type consistently instead of size_t
    
    On 16-bit msp430-elf size_t is either 16 bits or 20 bits, and so can't
    represent all values of the uint32_t type used for bitset::size_type.
    Using the smaller of size_t and uint32_t for size_type ensures it fits
    in size_t.
    
            PR libstdc++/88113
            * src/c++17/memory_resource.cc (bitset::size_type): Use the smaller
            of uint32_t and size_t.
            (bitset::size(), bitset::free(), bitset::update_next_word())
            (bitset::max_blocks_per_chunk(), bitset::max_word_index()): Use
            size_type consistently instead of size_t.
            (chunk): Adjust static_assert checking sizeof(chunk).

diff --git a/libstdc++-v3/src/c++17/memory_resource.cc b/libstdc++-v3/src/c++17/memory_resource.cc
index a3766311725..6198e6b68ca 100644
--- a/libstdc++-v3/src/c++17/memory_resource.cc
+++ b/libstdc++-v3/src/c++17/memory_resource.cc
@@ -252,11 +252,13 @@ namespace pmr
 
   namespace {
 
-  // Simple bitset with runtime size. Tracks used blocks in a pooled chunk.
+  // Simple bitset with runtime size.
+  // Tracks which blocks in a pool chunk are used/unused.
   struct bitset
   {
     using word = uint64_t;
-    using size_type = uint32_t;
+    using size_type // unsigned integer type with no more than 32 bits
+      = conditional_t<numeric_limits<size_t>::digits <= 32, size_t, uint32_t>;
 
     static constexpr unsigned bits_per_word = numeric_limits<word>::digits;
 
@@ -269,7 +271,7 @@ namespace pmr
       __builtin_memset(_M_words, 0, last_word * sizeof(*_M_words));
       // Set bits beyond _M_size, so they are not treated as free blocks:
       if (const size_type extra_bits = num_blocks % bits_per_word)
-	_M_words[last_word] = (word)-1 << extra_bits;
+	_M_words[last_word] = word(-1) << extra_bits;
       __glibcxx_assert( empty() );
       __glibcxx_assert( free() == num_blocks );
     }
@@ -278,12 +280,12 @@ namespace pmr
     ~bitset() = default;
 
     // Number of blocks
-    size_t size() const noexcept { return _M_size; }
+    size_type size() const noexcept { return _M_size; }
 
     // Number of free blocks (unset bits)
-    size_t free() const noexcept
+    size_type free() const noexcept
     {
-      size_t n = 0;
+      size_type n = 0;
       for (size_type i = _M_next_word; i < nwords(); ++i)
 	n += (bits_per_word - std::__popcount(_M_words[i]));
       return n;
@@ -376,7 +378,7 @@ namespace pmr
     // this function saturates _M_next_word at max_word_index().
     void update_next_word() noexcept
     {
-      size_t next = _M_next_word;
+      size_type next = _M_next_word;
       while (_M_words[next] == word(-1) && ++next < nwords())
 	{ }
       _M_next_word = std::min(next, max_word_index());
@@ -397,11 +399,11 @@ namespace pmr
     { return (_M_size + bits_per_word - 1) / bits_per_word; }
 
     // Maximum value that can be stored in bitset::_M_size member (approx 500k)
-    static constexpr size_t max_blocks_per_chunk() noexcept
-    { return (1ull << _S_size_digits) - 1; }
+    static constexpr size_type max_blocks_per_chunk() noexcept
+    { return (size_type(1) << _S_size_digits) - 1; }
 
     // Maximum value that can be stored in bitset::_M_next_word member (8191).
-    static constexpr size_t max_word_index() noexcept
+    static constexpr size_type max_word_index() noexcept
     { return (max_blocks_per_chunk() + bits_per_word - 1) / bits_per_word; }
 
     word* data() const noexcept { return _M_words; }
@@ -519,9 +521,12 @@ namespace pmr
     { return std::less<const void*>{}(p, c._M_p); }
   };
 
-  // For 64-bit this is 3*sizeof(void*) and for 32-bit it's 4*sizeof(void*).
+  // For 64-bit pointers this is the size of three pointers i.e. 24 bytes.
+  // For 32-bit and 20-bit pointers it's four pointers (16 bytes).
+  // For 16-bit pointers it's five pointers (10 bytes).
   // TODO pad 64-bit to 4*sizeof(void*) to avoid splitting across cache lines?
-  static_assert(sizeof(chunk) == 2 * sizeof(uint32_t) + 2 * sizeof(void*));
+  static_assert(sizeof(chunk)
+      == sizeof(bitset::size_type) + sizeof(uint32_t) + 2 * sizeof(void*));
 
   // An oversized allocation that doesn't fit in a pool.
   struct big_block

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]