diff options
| author | Paul Eggert | 2013-11-13 18:39:28 -0800 |
|---|---|---|
| committer | Paul Eggert | 2013-11-13 18:39:28 -0800 |
| commit | 2cf00efc1b0db0ddc26fa14239026dd2d12c7d59 (patch) | |
| tree | 1bd3fcc233230eb7e2ffdee78da9433b3915623e /src/data.c | |
| parent | d672ac3c611453c624948ed8cc2ced65cadc3400 (diff) | |
| download | emacs-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.c | 155 |
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 | ||
| 2969 | static bits_word | 2967 | static bits_word |
| 2970 | bool_vector_spare_mask (EMACS_INT nr_bits) | 2968 | bool_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 | 2977 | enum { 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." | 2979 | enum { 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 | |||
| 2987 | static bits_word | ||
| 2988 | shift_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 | |||
| 2997 | static int | ||
| 2998 | count_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 | |||
| 2985 | enum bool_vector_op { bool_vector_exclusive_or, | 3014 | enum 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 | ||
| 3086 | static bits_word | 3119 | static 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 | { |