1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/memory_utils.cc Tue Jan 19 23:26:49 2021 +0100
1.3 @@ -0,0 +1,111 @@
1.4 +#include "memory_utils.h"
1.5 +
1.6 +
1.7 +
1.8 +/* Return page 'n' for the configured page size. */
1.9 +
1.10 +offset_t page(unsigned int n)
1.11 +{
1.12 + return PAGE_SIZE * n;
1.13 +}
1.14 +
1.15 +/* Return the order of 'size', where 2 ** order yields the size. */
1.16 +
1.17 +unsigned int page_order(offset_t size)
1.18 +{
1.19 + /* Count zeros from the left, stopping at the first set bit, using the width
1.20 + of the size value (in bits, starting with the width in bytes) to
1.21 + calculate the position of this bit and thus the order of the value. */
1.22 +
1.23 + return sizeof(unsigned long) * 8 - 1 - __builtin_clzl(size);
1.24 +}
1.25 +
1.26 +/* Return 'value' rounded up to the nearest 'increment'. */
1.27 +
1.28 +offset_t round(offset_t value, offset_t increment)
1.29 +{
1.30 + return trunc(value + increment - 1, increment);
1.31 +}
1.32 +
1.33 +/* Return 'value' rounded up to the nearest multiple of 'increment'. */
1.34 +
1.35 +offset_t round_multiple(offset_t value, offset_t increment)
1.36 +{
1.37 + offset_t last = increment;
1.38 +
1.39 + while (1)
1.40 + {
1.41 + if (value < increment)
1.42 + return round(value, last);
1.43 +
1.44 + last = increment;
1.45 + increment *= 2;
1.46 + }
1.47 +}
1.48 +
1.49 +/* Return 'value' rounded down (or truncated) to the nearest 'increment'. */
1.50 +
1.51 +offset_t trunc(offset_t value, offset_t increment)
1.52 +{
1.53 + return (value / increment) * increment;
1.54 +}
1.55 +
1.56 +/* Return 'value' rounded down (or truncated) to the nearest multiple of
1.57 + 'increment'. */
1.58 +
1.59 +offset_t trunc_multiple(offset_t value, offset_t increment)
1.60 +{
1.61 + offset_t last = increment;
1.62 +
1.63 + while (1)
1.64 + {
1.65 + if (value < increment)
1.66 + return trunc(value, last);
1.67 +
1.68 + last = increment;
1.69 + increment *= 2;
1.70 + }
1.71 +}
1.72 +
1.73 +/* Find the maximum size aligned region within the region from 'start' to (but
1.74 + not including) 'end', with the given initial 'increment'. */
1.75 +
1.76 +offset_t max_multiple(offset_t start, offset_t end, offset_t increment)
1.77 +{
1.78 + /* The largest possible aligned region is derived from the region size. */
1.79 +
1.80 + offset_t size = trunc_multiple(end - start, increment);
1.81 +
1.82 + /* Apply the alignment to the start. */
1.83 +
1.84 + offset_t aligned = round(start, size);
1.85 +
1.86 + /* If the region is aligned, return the size. */
1.87 +
1.88 + if (aligned == start)
1.89 + return size;
1.90 +
1.91 + /* If the region is not aligned to the current size, recalculate the aligned
1.92 + size. */
1.93 +
1.94 + offset_t aligned_size;
1.95 +
1.96 + do
1.97 + {
1.98 + aligned_size = trunc_multiple(end - aligned, increment);
1.99 + size /= 2;
1.100 +
1.101 + /* Determine whether a smaller alignment could yield a larger aligned
1.102 + size. */
1.103 +
1.104 + if (aligned_size >= size)
1.105 + return aligned_size;
1.106 +
1.107 + aligned = round(start, size);
1.108 + }
1.109 + while (aligned > start);
1.110 +
1.111 + return aligned_size;
1.112 +}
1.113 +
1.114 +// vim: tabstop=4 expandtab shiftwidth=4