aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2013-11-13 18:39:28 -0800
committerPaul Eggert2013-11-13 18:39:28 -0800
commit2cf00efc1b0db0ddc26fa14239026dd2d12c7d59 (patch)
tree1bd3fcc233230eb7e2ffdee78da9433b3915623e /src
parentd672ac3c611453c624948ed8cc2ced65cadc3400 (diff)
downloademacs-2cf00efc1b0db0ddc26fa14239026dd2d12c7d59.tar.gz
emacs-2cf00efc1b0db0ddc26fa14239026dd2d12c7d59.zip
Simplify, port and tune bool vector implementation.
* configure.ac (BITSIZEOF_SIZE_T, SIZEOF_SIZE_T): Remove. * src/alloc.c (bool_vector_exact_payload_bytes) (bool_vector_payload_bytes): Remove. (bool_vector_fill): Return its argument. * src/alloc.c (bool_vector_fill): * src/lread.c (read1): * src/print.c (print_object): Simplify by using bool_vector_bytes. * src/alloc.c (make_uninit_bool_vector): New function, broken out from Fmake_bool_vector. (Fmake_bool_vector): Use it. Use tail call. (make_uninit_bool_vector, vector_nbytes): Simplify size calculations. * src/data.c (BITS_PER_ULL): New constant. (ULLONG_MAX, count_one_bits_ll): Fall back on long counterparts if long long versions don't exist. (shift_right_ull): New function. (count_one_bits_word): New function, replacing popcount_bits_word macro. Don't assume that bits_word is no wider than long long. (count_one_bits_word, count_trailing_zero_bits): Don't assume that bits_word is no wider than long long. * src/data.c (bool_vector_binop_driver, bool_vector_not): * src/fns.c (Fcopy_sequence): * src/lread.c (read1): Create an uninitialized destination, to avoid needless work. (internal_equal): Simplify. (Ffillarray): Prefer tail call. * src/data.c (bool_vector_binop_driver): Don't assume bit vectors always contain at least one word. (bits_word_to_host_endian): Prefer if to #if. Don't assume chars are narrower than ints. * src/data.c (Fbool_vector_count_matches, Fbool_vector_count_matches_at): * src/fns.c (Fcopy_sequence): Simplify and tune. * src/lisp.h (bits_word, BITS_WORD_MAX, BITS_PER_BITS_WORD): Don't try to port to hosts where bits_word values have holes; the code wouldn't work there anyway. Verify this assumption, though. (bool_vector_bytes): New function. (make_uninit_bool_vector): New decl. (bool_vector_fill): Now returns Lisp_Object.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog40
-rw-r--r--src/alloc.c87
-rw-r--r--src/data.c155
-rw-r--r--src/fns.c16
-rw-r--r--src/lisp.h24
-rw-r--r--src/lread.c6
-rw-r--r--src/print.c3
7 files changed, 196 insertions, 135 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 3861449cf5a..290b83a7ecf 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,45 @@
12013-11-14 Paul Eggert <eggert@cs.ucla.edu> 12013-11-14 Paul Eggert <eggert@cs.ucla.edu>
2 2
3 Simplify, port and tune bool vector implementation.
4 * alloc.c (bool_vector_exact_payload_bytes)
5 (bool_vector_payload_bytes): Remove.
6 (bool_vector_fill): Return its argument.
7 * alloc.c (bool_vector_fill):
8 * lread.c (read1):
9 * print.c (print_object):
10 Simplify by using bool_vector_bytes.
11 * alloc.c (make_uninit_bool_vector):
12 New function, broken out from Fmake_bool_vector.
13 (Fmake_bool_vector): Use it. Use tail call.
14 (make_uninit_bool_vector, vector_nbytes): Simplify size calculations.
15 * data.c (BITS_PER_ULL): New constant.
16 (ULLONG_MAX, count_one_bits_ll): Fall back on long counterparts
17 if long long versions don't exist.
18 (shift_right_ull): New function.
19 (count_one_bits_word): New function, replacing popcount_bits_word
20 macro. Don't assume that bits_word is no wider than long long.
21 (count_one_bits_word, count_trailing_zero_bits):
22 Don't assume that bits_word is no wider than long long.
23 * data.c (bool_vector_binop_driver, bool_vector_not):
24 * fns.c (Fcopy_sequence):
25 * lread.c (read1):
26 Create an uninitialized destination, to avoid needless work.
27 (internal_equal): Simplify.
28 (Ffillarray): Prefer tail call.
29 * data.c (bool_vector_binop_driver): Don't assume bit vectors always
30 contain at least one word.
31 (bits_word_to_host_endian): Prefer if to #if. Don't assume
32 chars are narrower than ints.
33 * data.c (Fbool_vector_count_matches, Fbool_vector_count_matches_at):
34 * fns.c (Fcopy_sequence):
35 Simplify and tune.
36 * lisp.h (bits_word, BITS_WORD_MAX, BITS_PER_BITS_WORD):
37 Don't try to port to hosts where bits_word values have holes; the
38 code wouldn't work there anyway. Verify this assumption, though.
39 (bool_vector_bytes): New function.
40 (make_uninit_bool_vector): New decl.
41 (bool_vector_fill): Now returns Lisp_Object.
42
3 * xfns.c (xic_create_fontsetname): 43 * xfns.c (xic_create_fontsetname):
4 * xrdb.c (gethomedir): Prefer tail calls. 44 * xrdb.c (gethomedir): Prefer tail calls.
5 45
diff --git a/src/alloc.c b/src/alloc.c
index bc5ed6d94bb..f12fdc5c861 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -2041,26 +2041,10 @@ INIT must be an integer that represents a character. */)
2041 return val; 2041 return val;
2042} 2042}
2043 2043
2044static EMACS_INT 2044/* Fill A with 1 bits if INIT is non-nil, and with 0 bits otherwise.
2045bool_vector_exact_payload_bytes (EMACS_INT nbits) 2045 Return A. */
2046{
2047 eassume (0 <= nbits);
2048 return (nbits + BOOL_VECTOR_BITS_PER_CHAR - 1) / BOOL_VECTOR_BITS_PER_CHAR;
2049}
2050
2051static EMACS_INT
2052bool_vector_payload_bytes (EMACS_INT nbits)
2053{
2054 EMACS_INT exact_needed_bytes = bool_vector_exact_payload_bytes (nbits);
2055 2046
2056 /* Always allocate at least one machine word of payload so that 2047Lisp_Object
2057 bool-vector operations in data.c don't need a special case
2058 for empty vectors. */
2059 return ROUNDUP (exact_needed_bytes + !exact_needed_bytes,
2060 sizeof (bits_word));
2061}
2062
2063void
2064bool_vector_fill (Lisp_Object a, Lisp_Object init) 2048bool_vector_fill (Lisp_Object a, Lisp_Object init)
2065{ 2049{
2066 EMACS_INT nbits = bool_vector_size (a); 2050 EMACS_INT nbits = bool_vector_size (a);
@@ -2068,48 +2052,50 @@ bool_vector_fill (Lisp_Object a, Lisp_Object init)
2068 { 2052 {
2069 unsigned char *data = bool_vector_uchar_data (a); 2053 unsigned char *data = bool_vector_uchar_data (a);
2070 int pattern = NILP (init) ? 0 : (1 << BOOL_VECTOR_BITS_PER_CHAR) - 1; 2054 int pattern = NILP (init) ? 0 : (1 << BOOL_VECTOR_BITS_PER_CHAR) - 1;
2071 ptrdiff_t nbytes = ((nbits + BOOL_VECTOR_BITS_PER_CHAR - 1) 2055 ptrdiff_t nbytes = bool_vector_bytes (nbits);
2072 / BOOL_VECTOR_BITS_PER_CHAR);
2073 int last_mask = ~ (~0 << ((nbits - 1) % BOOL_VECTOR_BITS_PER_CHAR + 1)); 2056 int last_mask = ~ (~0 << ((nbits - 1) % BOOL_VECTOR_BITS_PER_CHAR + 1));
2074 memset (data, pattern, nbytes - 1); 2057 memset (data, pattern, nbytes - 1);
2075 data[nbytes - 1] = pattern & last_mask; 2058 data[nbytes - 1] = pattern & last_mask;
2076 } 2059 }
2060 return a;
2077} 2061}
2078 2062
2079DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0, 2063/* Return a newly allocated, uninitialized bool vector of size NBITS. */
2080 doc: /* Return a new bool-vector of length LENGTH, using INIT for each element. 2064
2081LENGTH must be a number. INIT matters only in whether it is t or nil. */) 2065Lisp_Object
2082 (Lisp_Object length, Lisp_Object init) 2066make_uninit_bool_vector (EMACS_INT nbits)
2083{ 2067{
2084 Lisp_Object val; 2068 Lisp_Object val;
2085 struct Lisp_Bool_Vector *p; 2069 struct Lisp_Bool_Vector *p;
2086 EMACS_INT exact_payload_bytes, total_payload_bytes, needed_elements; 2070 EMACS_INT word_bytes, needed_elements;
2087 2071 word_bytes = bool_vector_words (nbits) * sizeof (bits_word);
2088 CHECK_NATNUM (length); 2072 needed_elements = ((bool_header_size - header_size + word_bytes
2089
2090 exact_payload_bytes = bool_vector_exact_payload_bytes (XFASTINT (length));
2091 total_payload_bytes = bool_vector_payload_bytes (XFASTINT (length));
2092
2093 needed_elements = ((bool_header_size - header_size + total_payload_bytes
2094 + word_size - 1) 2073 + word_size - 1)
2095 / word_size); 2074 / word_size);
2096
2097 p = (struct Lisp_Bool_Vector *) allocate_vector (needed_elements); 2075 p = (struct Lisp_Bool_Vector *) allocate_vector (needed_elements);
2098 XSETVECTOR (val, p); 2076 XSETVECTOR (val, p);
2099 XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0, 0); 2077 XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0, 0);
2100 2078 p->size = nbits;
2101 p->size = XFASTINT (length);
2102 bool_vector_fill (val, init);
2103 2079
2104 /* Clear padding at the end. */ 2080 /* Clear padding at the end. */
2105 eassume (exact_payload_bytes <= total_payload_bytes); 2081 if (nbits)
2106 memset (bool_vector_uchar_data (val) + exact_payload_bytes, 2082 p->data[bool_vector_words (nbits) - 1] = 0;
2107 0,
2108 total_payload_bytes - exact_payload_bytes);
2109 2083
2110 return val; 2084 return val;
2111} 2085}
2112 2086
2087DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0,
2088 doc: /* Return a new bool-vector of length LENGTH, using INIT for each element.
2089LENGTH must be a number. INIT matters only in whether it is t or nil. */)
2090 (Lisp_Object length, Lisp_Object init)
2091{
2092 Lisp_Object val;
2093
2094 CHECK_NATNUM (length);
2095 val = make_uninit_bool_vector (XFASTINT (length));
2096 return bool_vector_fill (val, init);
2097}
2098
2113 2099
2114/* Make a string from NBYTES bytes at CONTENTS, and compute the number 2100/* Make a string from NBYTES bytes at CONTENTS, and compute the number
2115 of characters from the contents. This string may be unibyte or 2101 of characters from the contents. This string may be unibyte or
@@ -2858,24 +2844,27 @@ static ptrdiff_t
2858vector_nbytes (struct Lisp_Vector *v) 2844vector_nbytes (struct Lisp_Vector *v)
2859{ 2845{
2860 ptrdiff_t size = v->header.size & ~ARRAY_MARK_FLAG; 2846 ptrdiff_t size = v->header.size & ~ARRAY_MARK_FLAG;
2847 ptrdiff_t nwords;
2861 2848
2862 if (size & PSEUDOVECTOR_FLAG) 2849 if (size & PSEUDOVECTOR_FLAG)
2863 { 2850 {
2864 if (PSEUDOVECTOR_TYPEP (&v->header, PVEC_BOOL_VECTOR)) 2851 if (PSEUDOVECTOR_TYPEP (&v->header, PVEC_BOOL_VECTOR))
2865 { 2852 {
2866 struct Lisp_Bool_Vector *bv = (struct Lisp_Bool_Vector *) v; 2853 struct Lisp_Bool_Vector *bv = (struct Lisp_Bool_Vector *) v;
2867 ptrdiff_t payload_bytes = bool_vector_payload_bytes (bv->size); 2854 ptrdiff_t word_bytes = (bool_vector_words (bv->size)
2868 size = bool_header_size + payload_bytes; 2855 * sizeof (bits_word));
2856 ptrdiff_t boolvec_bytes = bool_header_size + word_bytes;
2857 verify (header_size <= bool_header_size);
2858 nwords = (boolvec_bytes - header_size + word_size - 1) / word_size;
2869 } 2859 }
2870 else 2860 else
2871 size = (header_size 2861 nwords = ((size & PSEUDOVECTOR_SIZE_MASK)
2872 + ((size & PSEUDOVECTOR_SIZE_MASK) 2862 + ((size & PSEUDOVECTOR_REST_MASK)
2873 + ((size & PSEUDOVECTOR_REST_MASK) 2863 >> PSEUDOVECTOR_SIZE_BITS));
2874 >> PSEUDOVECTOR_SIZE_BITS)) * word_size);
2875 } 2864 }
2876 else 2865 else
2877 size = header_size + size * word_size; 2866 nwords = size;
2878 return vroundup (size); 2867 return vroundup (header_size + word_size * nwords);
2879} 2868}
2880 2869
2881/* Release extra resources still in use by VECTOR, which may be any 2870/* Release extra resources still in use by VECTOR, which may be any
diff --git a/src/data.c b/src/data.c
index 4043fbe279b..7ff7ac6b130 100644
--- a/src/data.c
+++ b/src/data.c
@@ -2962,9 +2962,7 @@ lowercase l) for small endian machines. */)
2962 2962
2963/* Because we round up the bool vector allocate size to word_size 2963/* Because we round up the bool vector allocate size to word_size
2964 units, we can safely read past the "end" of the vector in the 2964 units, we can safely read past the "end" of the vector in the
2965 operations below. These extra bits are always zero. Also, we 2965 operations below. These extra bits are always zero. */
2966 always allocate bool vectors with at least one bits_word of storage so
2967 that we don't have to special-case empty bit vectors. */
2968 2966
2969static bits_word 2967static bits_word
2970bool_vector_spare_mask (EMACS_INT nr_bits) 2968bool_vector_spare_mask (EMACS_INT nr_bits)
@@ -2972,16 +2970,47 @@ bool_vector_spare_mask (EMACS_INT nr_bits)
2972 return (((bits_word) 1) << (nr_bits % BITS_PER_BITS_WORD)) - 1; 2970 return (((bits_word) 1) << (nr_bits % BITS_PER_BITS_WORD)) - 1;
2973} 2971}
2974 2972
2975#if BITS_WORD_MAX <= UINT_MAX 2973/* Info about unsigned long long, falling back on unsigned long
2976# define popcount_bits_word count_one_bits 2974 if unsigned long long is not available. */
2977#elif BITS_WORD_MAX <= ULONG_MAX 2975
2978# define popcount_bits_word count_one_bits_l 2976#if HAVE_UNSIGNED_LONG_LONG_INT
2979#elif BITS_WORD_MAX <= ULLONG_MAX 2977enum { BITS_PER_ULL = CHAR_BIT * sizeof (unsigned long long) };
2980# define popcount_bits_word count_one_bits_ll
2981#else 2978#else
2982# error "bits_word wider than long long? Please file a bug report." 2979enum { BITS_PER_ULL = CHAR_BIT * sizeof (unsigned long) };
2980# define ULLONG_MAX ULONG_MAX
2981# define count_one_bits_ll count_one_bits_l
2983#endif 2982#endif
2984 2983
2984/* Shift VAL right by the width of an unsigned long long.
2985 BITS_PER_ULL must be less than BITS_PER_BITS_WORD. */
2986
2987static bits_word
2988shift_right_ull (bits_word w)
2989{
2990 /* Pacify bogus GCC warning about shift count exceeding type width. */
2991 int shift = BITS_PER_ULL - BITS_PER_BITS_WORD < 0 ? BITS_PER_ULL : 0;
2992 return w >> shift;
2993}
2994
2995/* Return the number of 1 bits in W. */
2996
2997static int
2998count_one_bits_word (bits_word w)
2999{
3000 if (BITS_WORD_MAX <= UINT_MAX)
3001 return count_one_bits (w);
3002 else if (BITS_WORD_MAX <= ULONG_MAX)
3003 return count_one_bits_l (w);
3004 else
3005 {
3006 int i = 0, count = 0;
3007 while (count += count_one_bits_ll (w),
3008 BITS_PER_BITS_WORD <= (i += BITS_PER_ULL))
3009 w = shift_right_ull (w);
3010 return count;
3011 }
3012}
3013
2985enum bool_vector_op { bool_vector_exclusive_or, 3014enum bool_vector_op { bool_vector_exclusive_or,
2986 bool_vector_union, 3015 bool_vector_union,
2987 bool_vector_intersection, 3016 bool_vector_intersection,
@@ -2997,7 +3026,7 @@ bool_vector_binop_driver (Lisp_Object op1,
2997 EMACS_INT nr_bits; 3026 EMACS_INT nr_bits;
2998 bits_word *adata, *bdata, *cdata; 3027 bits_word *adata, *bdata, *cdata;
2999 ptrdiff_t i; 3028 ptrdiff_t i;
3000 bits_word changed = 0; 3029 bool changed = 0;
3001 bits_word mword; 3030 bits_word mword;
3002 ptrdiff_t nr_words; 3031 ptrdiff_t nr_words;
3003 3032
@@ -3010,7 +3039,7 @@ bool_vector_binop_driver (Lisp_Object op1,
3010 3039
3011 if (NILP (dest)) 3040 if (NILP (dest))
3012 { 3041 {
3013 dest = Fmake_bool_vector (make_number (nr_bits), Qnil); 3042 dest = make_uninit_bool_vector (nr_bits);
3014 changed = 1; 3043 changed = 1;
3015 } 3044 }
3016 else 3045 else
@@ -3025,8 +3054,8 @@ bool_vector_binop_driver (Lisp_Object op1,
3025 adata = bool_vector_data (dest); 3054 adata = bool_vector_data (dest);
3026 bdata = bool_vector_data (op1); 3055 bdata = bool_vector_data (op1);
3027 cdata = bool_vector_data (op2); 3056 cdata = bool_vector_data (op2);
3028 i = 0; 3057
3029 do 3058 for (i = 0; i < nr_words; i++)
3030 { 3059 {
3031 if (op == bool_vector_exclusive_or) 3060 if (op == bool_vector_exclusive_or)
3032 mword = bdata[i] ^ cdata[i]; 3061 mword = bdata[i] ^ cdata[i];
@@ -3039,14 +3068,12 @@ bool_vector_binop_driver (Lisp_Object op1,
3039 else 3068 else
3040 abort (); 3069 abort ();
3041 3070
3042 changed |= adata[i] ^ mword; 3071 if (! changed)
3072 changed = adata[i] != mword;
3043 3073
3044 if (op != bool_vector_subsetp) 3074 if (op != bool_vector_subsetp)
3045 adata[i] = mword; 3075 adata[i] = mword;
3046
3047 i++;
3048 } 3076 }
3049 while (i < nr_words);
3050 3077
3051 return changed ? dest : Qnil; 3078 return changed ? dest : Qnil;
3052} 3079}
@@ -3060,27 +3087,33 @@ count_trailing_zero_bits (bits_word val)
3060 return count_trailing_zeros (val); 3087 return count_trailing_zeros (val);
3061 if (BITS_WORD_MAX == ULONG_MAX) 3088 if (BITS_WORD_MAX == ULONG_MAX)
3062 return count_trailing_zeros_l (val); 3089 return count_trailing_zeros_l (val);
3063# if HAVE_UNSIGNED_LONG_LONG_INT
3064 if (BITS_WORD_MAX == ULLONG_MAX) 3090 if (BITS_WORD_MAX == ULLONG_MAX)
3065 return count_trailing_zeros_ll (val); 3091 return count_trailing_zeros_ll (val);
3066# endif
3067 3092
3068 /* The rest of this code is for the unlikely platform where bits_word differs 3093 /* The rest of this code is for the unlikely platform where bits_word differs
3069 in width from unsigned int, unsigned long, and unsigned long long. */ 3094 in width from unsigned int, unsigned long, and unsigned long long. */
3070 if (val == 0) 3095 val |= ~ BITS_WORD_MAX;
3071 return CHAR_BIT * sizeof (val);
3072 if (BITS_WORD_MAX <= UINT_MAX) 3096 if (BITS_WORD_MAX <= UINT_MAX)
3073 return count_trailing_zeros (val); 3097 return count_trailing_zeros (val);
3074 if (BITS_WORD_MAX <= ULONG_MAX) 3098 if (BITS_WORD_MAX <= ULONG_MAX)
3075 return count_trailing_zeros_l (val); 3099 return count_trailing_zeros_l (val);
3076 { 3100 else
3077# if HAVE_UNSIGNED_LONG_LONG_INT 3101 {
3078 verify (BITS_WORD_MAX <= ULLONG_MAX); 3102 int count;
3079 return count_trailing_zeros_ll (val); 3103 for (count = 0;
3080# else 3104 count < BITS_PER_BITS_WORD - BITS_PER_ULL;
3081 verify (BITS_WORD_MAX <= ULONG_MAX); 3105 count += BITS_PER_ULL)
3082# endif 3106 {
3083 } 3107 if (val & ULLONG_MAX)
3108 return count + count_trailing_zeros_ll (val);
3109 val = shift_right_ull (val);
3110 }
3111
3112 if (BITS_PER_BITS_WORD % BITS_PER_ULL != 0
3113 && BITS_WORD_MAX == (bits_word) -1)
3114 val |= (bits_word) 1 << (BITS_PER_BITS_WORD % BITS_PER_ULL);
3115 return count + count_trailing_zeros_ll (val);
3116 }
3084} 3117}
3085 3118
3086static bits_word 3119static bits_word
@@ -3088,20 +3121,24 @@ bits_word_to_host_endian (bits_word val)
3088{ 3121{
3089#ifndef WORDS_BIGENDIAN 3122#ifndef WORDS_BIGENDIAN
3090 return val; 3123 return val;
3091#elif BITS_WORD_MAX >> 31 == 1
3092 return bswap_32 (val);
3093#elif BITS_WORD_MAX >> 31 >> 31 >> 1 == 1
3094 return bswap_64 (val);
3095#else 3124#else
3096 int i; 3125 if (BITS_WORD_MAX >> 31 == 1)
3097 bits_word r = 0; 3126 return bswap_32 (val);
3098 for (i = 0; i < sizeof val; i++) 3127# if HAVE_UNSIGNED_LONG_LONG
3099 { 3128 if (BITS_WORD_MAX >> 31 >> 31 >> 1 == 1)
3100 r = ((r << 1 << (CHAR_BIT - 1)) 3129 return bswap_64 (val);
3101 | (val & ((1u << 1 << (CHAR_BIT - 1)) - 1))); 3130# endif
3102 val = val >> 1 >> (CHAR_BIT - 1); 3131 {
3103 } 3132 int i;
3104 return r; 3133 bits_word r = 0;
3134 for (i = 0; i < sizeof val; i++)
3135 {
3136 r = ((r << 1 << (CHAR_BIT - 1))
3137 | (val & ((1u << 1 << (CHAR_BIT - 1)) - 1)));
3138 val = val >> 1 >> (CHAR_BIT - 1);
3139 }
3140 return r;
3141 }
3105#endif 3142#endif
3106} 3143}
3107 3144
@@ -3174,7 +3211,7 @@ Return the destination vector. */)
3174 nr_bits = bool_vector_size (a); 3211 nr_bits = bool_vector_size (a);
3175 3212
3176 if (NILP (b)) 3213 if (NILP (b))
3177 b = Fmake_bool_vector (make_number (nr_bits), Qnil); 3214 b = make_uninit_bool_vector (nr_bits);
3178 else 3215 else
3179 { 3216 {
3180 CHECK_BOOL_VECTOR (b); 3217 CHECK_BOOL_VECTOR (b);
@@ -3208,27 +3245,20 @@ A must be a bool vector. B is a generalized bool. */)
3208 EMACS_INT count; 3245 EMACS_INT count;
3209 EMACS_INT nr_bits; 3246 EMACS_INT nr_bits;
3210 bits_word *adata; 3247 bits_word *adata;
3211 bits_word match; 3248 ptrdiff_t i, nwords;
3212 ptrdiff_t i;
3213 3249
3214 CHECK_BOOL_VECTOR (a); 3250 CHECK_BOOL_VECTOR (a);
3215 3251
3216 nr_bits = bool_vector_size (a); 3252 nr_bits = bool_vector_size (a);
3253 nwords = bool_vector_words (nr_bits);
3217 count = 0; 3254 count = 0;
3218 match = NILP (b) ? BITS_WORD_MAX : 0;
3219 adata = bool_vector_data (a); 3255 adata = bool_vector_data (a);
3220 3256
3221 for (i = 0; i < nr_bits / BITS_PER_BITS_WORD; ++i) 3257 for (i = 0; i < nwords; i++)
3222 count += popcount_bits_word (adata[i] ^ match); 3258 count += count_one_bits_word (adata[i]);
3223
3224 /* Mask out trailing parts of final mword. */
3225 if (nr_bits % BITS_PER_BITS_WORD)
3226 {
3227 bits_word mword = adata[i] ^ match;
3228 mword = bits_word_to_host_endian (mword);
3229 count += popcount_bits_word (mword & bool_vector_spare_mask (nr_bits));
3230 }
3231 3259
3260 if (NILP (b))
3261 count = nr_bits - count;
3232 return make_number (count); 3262 return make_number (count);
3233} 3263}
3234 3264
@@ -3246,7 +3276,7 @@ index into the vector. */)
3246 bits_word *adata; 3276 bits_word *adata;
3247 bits_word twiddle; 3277 bits_word twiddle;
3248 bits_word mword; /* Machine word. */ 3278 bits_word mword; /* Machine word. */
3249 ptrdiff_t pos; 3279 ptrdiff_t pos, pos0;
3250 ptrdiff_t nr_words; 3280 ptrdiff_t nr_words;
3251 3281
3252 CHECK_BOOL_VECTOR (a); 3282 CHECK_BOOL_VECTOR (a);
@@ -3273,8 +3303,8 @@ index into the vector. */)
3273 mword = bits_word_to_host_endian (adata[pos]); 3303 mword = bits_word_to_host_endian (adata[pos]);
3274 mword ^= twiddle; 3304 mword ^= twiddle;
3275 mword >>= offset; 3305 mword >>= offset;
3306 mword |= (bits_word) 1 << (BITS_PER_BITS_WORD - offset);
3276 count = count_trailing_zero_bits (mword); 3307 count = count_trailing_zero_bits (mword);
3277 count = min (count, BITS_PER_BITS_WORD - offset);
3278 pos++; 3308 pos++;
3279 if (count + offset < BITS_PER_BITS_WORD) 3309 if (count + offset < BITS_PER_BITS_WORD)
3280 return make_number (count); 3310 return make_number (count);
@@ -3283,11 +3313,10 @@ index into the vector. */)
3283 /* Scan whole words until we either reach the end of the vector or 3313 /* Scan whole words until we either reach the end of the vector or
3284 find an mword that doesn't completely match. twiddle is 3314 find an mword that doesn't completely match. twiddle is
3285 endian-independent. */ 3315 endian-independent. */
3316 pos0 = pos;
3286 while (pos < nr_words && adata[pos] == twiddle) 3317 while (pos < nr_words && adata[pos] == twiddle)
3287 { 3318 pos++;
3288 count += BITS_PER_BITS_WORD; 3319 count += (pos - pos0) * BITS_PER_BITS_WORD;
3289 ++pos;
3290 }
3291 3320
3292 if (pos < nr_words) 3321 if (pos < nr_words)
3293 { 3322 {
diff --git a/src/fns.c b/src/fns.c
index 44b70af6eb5..93829fb1d62 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -435,13 +435,10 @@ with the original. */)
435 435
436 if (BOOL_VECTOR_P (arg)) 436 if (BOOL_VECTOR_P (arg))
437 { 437 {
438 Lisp_Object val; 438 EMACS_INT nbits = bool_vector_size (arg);
439 ptrdiff_t size_in_chars 439 ptrdiff_t nbytes = bool_vector_bytes (nbits);
440 = ((bool_vector_size (arg) + BOOL_VECTOR_BITS_PER_CHAR - 1) 440 Lisp_Object val = make_uninit_bool_vector (nbits);
441 / BOOL_VECTOR_BITS_PER_CHAR); 441 memcpy (bool_vector_data (val), bool_vector_data (arg), nbytes);
442
443 val = Fmake_bool_vector (Flength (arg), Qnil);
444 memcpy (bool_vector_data (val), bool_vector_data (arg), size_in_chars);
445 return val; 442 return val;
446 } 443 }
447 444
@@ -2066,8 +2063,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props)
2066 if (size != bool_vector_size (o2)) 2063 if (size != bool_vector_size (o2))
2067 return 0; 2064 return 0;
2068 if (memcmp (bool_vector_data (o1), bool_vector_data (o2), 2065 if (memcmp (bool_vector_data (o1), bool_vector_data (o2),
2069 ((size + BOOL_VECTOR_BITS_PER_CHAR - 1) 2066 bool_vector_bytes (size)))
2070 / BOOL_VECTOR_BITS_PER_CHAR)))
2071 return 0; 2067 return 0;
2072 return 1; 2068 return 1;
2073 } 2069 }
@@ -2157,7 +2153,7 @@ ARRAY is a vector, string, char-table, or bool-vector. */)
2157 p[idx] = charval; 2153 p[idx] = charval;
2158 } 2154 }
2159 else if (BOOL_VECTOR_P (array)) 2155 else if (BOOL_VECTOR_P (array))
2160 bool_vector_fill (array, item); 2156 return bool_vector_fill (array, item);
2161 else 2157 else
2162 wrong_type_argument (Qarrayp, array); 2158 wrong_type_argument (Qarrayp, array);
2163 return array; 2159 return array;
diff --git a/src/lisp.h b/src/lisp.h
index 2b197cd32b1..72e5dad8ca3 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -92,16 +92,16 @@ enum { BOOL_VECTOR_BITS_PER_CHAR =
92/* An unsigned integer type representing a fixed-length bit sequence, 92/* An unsigned integer type representing a fixed-length bit sequence,
93 suitable for words in a Lisp bool vector. Normally it is size_t 93 suitable for words in a Lisp bool vector. Normally it is size_t
94 for speed, but it is unsigned char on weird platforms. */ 94 for speed, but it is unsigned char on weird platforms. */
95#if (BITSIZEOF_SIZE_T == CHAR_BIT * SIZEOF_SIZE_T \ 95#if BOOL_VECTOR_BITS_PER_CHAR == CHAR_BIT
96 && BOOL_VECTOR_BITS_PER_CHAR == CHAR_BIT)
97typedef size_t bits_word; 96typedef size_t bits_word;
98#define BITS_WORD_MAX SIZE_MAX 97# define BITS_WORD_MAX SIZE_MAX
99enum { BITS_PER_BITS_WORD = CHAR_BIT * sizeof (bits_word) }; 98enum { BITS_PER_BITS_WORD = CHAR_BIT * sizeof (bits_word) };
100#else 99#else
101typedef unsigned char bits_word; 100typedef unsigned char bits_word;
102#define BITS_WORD_MAX ((1u << BOOL_VECTOR_BITS_PER_CHAR) - 1) 101# define BITS_WORD_MAX ((1u << BOOL_VECTOR_BITS_PER_CHAR) - 1)
103enum { BITS_PER_BITS_WORD = BOOL_VECTOR_BITS_PER_CHAR }; 102enum { BITS_PER_BITS_WORD = BOOL_VECTOR_BITS_PER_CHAR };
104#endif 103#endif
104verify (BITS_WORD_MAX >> (BITS_PER_BITS_WORD - 1) == 1);
105 105
106/* Number of bits in some machine integer types. */ 106/* Number of bits in some machine integer types. */
107enum 107enum
@@ -1212,7 +1212,9 @@ struct Lisp_Bool_Vector
1212 struct vectorlike_header header; 1212 struct vectorlike_header header;
1213 /* This is the size in bits. */ 1213 /* This is the size in bits. */
1214 EMACS_INT size; 1214 EMACS_INT size;
1215 /* This contains the actual bits, packed into bytes. */ 1215 /* The actual bits, packed into bytes.
1216 The bits are in little-endian order in the bytes, and
1217 the bytes are in little-endian order in the words. */
1216 bits_word data[FLEXIBLE_ARRAY_MEMBER]; 1218 bits_word data[FLEXIBLE_ARRAY_MEMBER];
1217 }; 1219 };
1218 1220
@@ -1236,7 +1238,7 @@ bool_vector_uchar_data (Lisp_Object a)
1236 return (unsigned char *) bool_vector_data (a); 1238 return (unsigned char *) bool_vector_data (a);
1237} 1239}
1238 1240
1239/* The number of data words in a bool vector with SIZE bits. */ 1241/* The number of data words and bytes in a bool vector with SIZE bits. */
1240 1242
1241INLINE EMACS_INT 1243INLINE EMACS_INT
1242bool_vector_words (EMACS_INT size) 1244bool_vector_words (EMACS_INT size)
@@ -1245,6 +1247,13 @@ bool_vector_words (EMACS_INT size)
1245 return (size + BITS_PER_BITS_WORD - 1) / BITS_PER_BITS_WORD; 1247 return (size + BITS_PER_BITS_WORD - 1) / BITS_PER_BITS_WORD;
1246} 1248}
1247 1249
1250INLINE EMACS_INT
1251bool_vector_bytes (EMACS_INT size)
1252{
1253 eassume (0 <= size && size <= EMACS_INT_MAX - (BITS_PER_BITS_WORD - 1));
1254 return (size + BOOL_VECTOR_BITS_PER_CHAR - 1) / BOOL_VECTOR_BITS_PER_CHAR;
1255}
1256
1248/* True if A's Ith bit is set. */ 1257/* True if A's Ith bit is set. */
1249 1258
1250INLINE bool 1259INLINE bool
@@ -3588,7 +3597,8 @@ list4i (EMACS_INT x, EMACS_INT y, EMACS_INT w, EMACS_INT h)
3588 make_number (w), make_number (h)); 3597 make_number (w), make_number (h));
3589} 3598}
3590 3599
3591extern void bool_vector_fill (Lisp_Object, Lisp_Object); 3600extern Lisp_Object make_uninit_bool_vector (EMACS_INT);
3601extern Lisp_Object bool_vector_fill (Lisp_Object, Lisp_Object);
3592extern _Noreturn void string_overflow (void); 3602extern _Noreturn void string_overflow (void);
3593extern Lisp_Object make_string (const char *, ptrdiff_t); 3603extern Lisp_Object make_string (const char *, ptrdiff_t);
3594extern Lisp_Object make_formatted_string (char *, const char *, ...) 3604extern Lisp_Object make_formatted_string (char *, const char *, ...)
diff --git a/src/lread.c b/src/lread.c
index 7e4f5d38d09..6c1b17f62b7 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -2577,9 +2577,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
2577 if (c == '"') 2577 if (c == '"')
2578 { 2578 {
2579 Lisp_Object tmp, val; 2579 Lisp_Object tmp, val;
2580 EMACS_INT size_in_chars 2580 EMACS_INT size_in_chars = bool_vector_bytes (XFASTINT (length));
2581 = ((XFASTINT (length) + BOOL_VECTOR_BITS_PER_CHAR - 1)
2582 / BOOL_VECTOR_BITS_PER_CHAR);
2583 unsigned char *data; 2581 unsigned char *data;
2584 2582
2585 UNREAD (c); 2583 UNREAD (c);
@@ -2594,7 +2592,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
2594 == (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR))) 2592 == (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR)))
2595 invalid_syntax ("#&..."); 2593 invalid_syntax ("#&...");
2596 2594
2597 val = Fmake_bool_vector (length, Qnil); 2595 val = make_uninit_bool_vector (XFASTINT (length));
2598 data = bool_vector_uchar_data (val); 2596 data = bool_vector_uchar_data (val);
2599 memcpy (data, SDATA (tmp), size_in_chars); 2597 memcpy (data, SDATA (tmp), size_in_chars);
2600 /* Clear the extraneous bits in the last byte. */ 2598 /* Clear the extraneous bits in the last byte. */
diff --git a/src/print.c b/src/print.c
index 6eda6a86fc4..e3c56a6de62 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1705,8 +1705,7 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
1705 unsigned char c; 1705 unsigned char c;
1706 struct gcpro gcpro1; 1706 struct gcpro gcpro1;
1707 EMACS_INT size = bool_vector_size (obj); 1707 EMACS_INT size = bool_vector_size (obj);
1708 ptrdiff_t size_in_chars = ((size + BOOL_VECTOR_BITS_PER_CHAR - 1) 1708 ptrdiff_t size_in_chars = bool_vector_bytes (size);
1709 / BOOL_VECTOR_BITS_PER_CHAR);
1710 ptrdiff_t real_size_in_chars = size_in_chars; 1709 ptrdiff_t real_size_in_chars = size_in_chars;
1711 GCPRO1 (obj); 1710 GCPRO1 (obj);
1712 1711