aboutsummaryrefslogtreecommitdiffstats
path: root/src/data.c
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/data.c
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/data.c')
-rw-r--r--src/data.c155
1 files changed, 92 insertions, 63 deletions
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 {