diff options
| author | Daniel Colascione | 2013-09-22 01:31:55 -0800 |
|---|---|---|
| committer | Daniel Colascione | 2013-09-22 01:31:55 -0800 |
| commit | 3e0b94e7ff1fc69b077322d672ef5d0b668541c3 (patch) | |
| tree | 9927abd073960f2460f05a43ae9467cd82c00b9b /src | |
| parent | 76880d884d87d0bc674249e292ccda70f31cca0e (diff) | |
| download | emacs-3e0b94e7ff1fc69b077322d672ef5d0b668541c3.tar.gz emacs-3e0b94e7ff1fc69b077322d672ef5d0b668541c3.zip | |
Add set operations for bool-vector.
http://lists.gnu.org/archive/html/emacs-devel/2013-09/msg00404.html
* data.c (Qbool_vector_p): New symbol.
(bool_vector_spare_mask,popcount_size_t_generic)
(popcount_size_t_msc,popcount_size_t_gcc)
(popcount_size_t)
(bool_vector_binop_driver)
(count_trailing_zero_bits,size_t_to_host_endian)
(Fbool_vector_exclusive_or)
(Fbool_vector_union)
(Fbool_vector_intersection,Fbool_vector_set_difference)
(Fbool_vector_subsetp,Fbool_vector_not)
(Fbool_vector_count_matches)
(Fbool_vector_count_matches_at): New functions.
(syms_of_data): Intern new symbol, functions.
* alloc.c (bool_vector_payload_bytes): New function.
(Fmake_bool_vector): Instead of calling Fmake_vector,
which performs redundant initialization and argument checking,
just call allocate_vector ourselves. Make sure we clear any
terminating padding to zero.
(vector_nbytes,sweep_vectors): Use bool_vector_payload_bytes
instead of open-coding the size calculation.
(vroundup_ct): New macro.
(vroundup): Assume argument >= 0; invoke vroundup_ct.
* casetab.c (shuffle,set_identity): Change lint_assume to assume.
* composite.c (composition_gstring_put_cache): Change
lint_assume to assume.
* conf_post.h (assume): New macro.
(lint_assume): Remove.
* dispnew.c (update_frame_1): Change lint_assume to assume.
* ftfont.c (ftfont_shape_by_flt): Change lint_assume
to assume.
* image.c (gif_load): Change lint_assume to assume.
* lisp.h (eassert_and_assume): New macro.
(Qbool_vector_p): Declare.
(CHECK_BOOL_VECTOR,ROUNDUP,BITS_PER_SIZE_T): New macros.
(swap16,swap32,swap64): New inline functions.
* macfont.c (macfont_shape): Change lint_assume to assume.
* ralloc.c: Rename ROUNDUP to PAGE_ROUNDUP throughout.
* xsettings.c (parse_settings): Use new swap16 and
swap32 from lisp.h instead of file-specific macros.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 42 | ||||
| -rw-r--r-- | src/alloc.c | 103 | ||||
| -rw-r--r-- | src/casetab.c | 4 | ||||
| -rw-r--r-- | src/composite.c | 2 | ||||
| -rw-r--r-- | src/conf_post.h | 16 | ||||
| -rw-r--r-- | src/data.c | 462 | ||||
| -rw-r--r-- | src/dispnew.c | 2 | ||||
| -rw-r--r-- | src/ftfont.c | 2 | ||||
| -rw-r--r-- | src/image.c | 2 | ||||
| -rw-r--r-- | src/intervals.c | 2 | ||||
| -rw-r--r-- | src/lisp.h | 50 | ||||
| -rw-r--r-- | src/macfont.m | 2 | ||||
| -rw-r--r-- | src/ralloc.c | 22 | ||||
| -rw-r--r-- | src/xsettings.c | 11 |
14 files changed, 656 insertions, 66 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 1442650d432..7c3a29c5d86 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,45 @@ | |||
| 1 | 2013-09-22 Daniel Colascione <dancol@dancol.org> | ||
| 2 | |||
| 3 | * data.c (Qbool_vector_p): New symbol. | ||
| 4 | (bool_vector_spare_mask,popcount_size_t_generic) | ||
| 5 | (popcount_size_t_msc,popcount_size_t_gcc) | ||
| 6 | (popcount_size_t) | ||
| 7 | (bool_vector_binop_driver) | ||
| 8 | (count_trailing_zero_bits,size_t_to_host_endian) | ||
| 9 | (Fbool_vector_exclusive_or) | ||
| 10 | (Fbool_vector_union) | ||
| 11 | (Fbool_vector_intersection,Fbool_vector_set_difference) | ||
| 12 | (Fbool_vector_subsetp,Fbool_vector_not) | ||
| 13 | (Fbool_vector_count_matches) | ||
| 14 | (Fbool_vector_count_matches_at): New functions. | ||
| 15 | (syms_of_data): Intern new symbol, functions. | ||
| 16 | * alloc.c (bool_vector_payload_bytes): New function. | ||
| 17 | (Fmake_bool_vector): Instead of calling Fmake_vector, | ||
| 18 | which performs redundant initialization and argument checking, | ||
| 19 | just call allocate_vector ourselves. Make sure we clear any | ||
| 20 | terminating padding to zero. | ||
| 21 | (vector_nbytes,sweep_vectors): Use bool_vector_payload_bytes | ||
| 22 | instead of open-coding the size calculation. | ||
| 23 | (vroundup_ct): New macro. | ||
| 24 | (vroundup): Assume argument >= 0; invoke vroundup_ct. | ||
| 25 | * casetab.c (shuffle,set_identity): Change lint_assume to assume. | ||
| 26 | * composite.c (composition_gstring_put_cache): Change | ||
| 27 | lint_assume to assume. | ||
| 28 | * conf_post.h (assume): New macro. | ||
| 29 | (lint_assume): Remove. | ||
| 30 | * dispnew.c (update_frame_1): Change lint_assume to assume. | ||
| 31 | * ftfont.c (ftfont_shape_by_flt): Change lint_assume | ||
| 32 | to assume. | ||
| 33 | * image.c (gif_load): Change lint_assume to assume. | ||
| 34 | * lisp.h (eassert_and_assume): New macro. | ||
| 35 | (Qbool_vector_p): Declare. | ||
| 36 | (CHECK_BOOL_VECTOR,ROUNDUP,BITS_PER_SIZE_T): New macros. | ||
| 37 | (swap16,swap32,swap64): New inline functions. | ||
| 38 | * macfont.c (macfont_shape): Change lint_assume to assume. | ||
| 39 | * ralloc.c: Rename ROUNDUP to PAGE_ROUNDUP throughout. | ||
| 40 | * xsettings.c (parse_settings): Use new swap16 and | ||
| 41 | swap32 from lisp.h instead of file-specific macros. | ||
| 42 | |||
| 1 | 2013-09-22 Eli Zaretskii <eliz@gnu.org> | 43 | 2013-09-22 Eli Zaretskii <eliz@gnu.org> |
| 2 | 44 | ||
| 3 | * xdisp.c (try_window_id): Don't abort if cursor row could not be | 45 | * xdisp.c (try_window_id): Don't abort if cursor row could not be |
diff --git a/src/alloc.c b/src/alloc.c index de73ce9bae0..847b3c88bbe 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -2001,6 +2001,35 @@ INIT must be an integer that represents a character. */) | |||
| 2001 | return val; | 2001 | return val; |
| 2002 | } | 2002 | } |
| 2003 | 2003 | ||
| 2004 | verify (sizeof (size_t) * CHAR_BIT == BITS_PER_SIZE_T); | ||
| 2005 | verify ((BITS_PER_SIZE_T & (BITS_PER_SIZE_T - 1)) == 0); | ||
| 2006 | |||
| 2007 | static | ||
| 2008 | ptrdiff_t | ||
| 2009 | bool_vector_payload_bytes (ptrdiff_t nr_bits, | ||
| 2010 | ptrdiff_t* exact_needed_bytes_out) | ||
| 2011 | { | ||
| 2012 | ptrdiff_t exact_needed_bytes; | ||
| 2013 | ptrdiff_t needed_bytes; | ||
| 2014 | |||
| 2015 | eassert_and_assume (nr_bits >= 0); | ||
| 2016 | |||
| 2017 | exact_needed_bytes = ROUNDUP ((size_t) nr_bits, CHAR_BIT) / CHAR_BIT; | ||
| 2018 | needed_bytes = ROUNDUP ((size_t) nr_bits, BITS_PER_SIZE_T) / CHAR_BIT; | ||
| 2019 | |||
| 2020 | if (needed_bytes == 0) | ||
| 2021 | { | ||
| 2022 | /* Always allocate at least one machine word of payload so that | ||
| 2023 | bool-vector operations in data.c don't need a special case | ||
| 2024 | for empty vectors. */ | ||
| 2025 | needed_bytes = sizeof (size_t); | ||
| 2026 | } | ||
| 2027 | |||
| 2028 | if (exact_needed_bytes_out != NULL) | ||
| 2029 | *exact_needed_bytes_out = exact_needed_bytes; | ||
| 2030 | |||
| 2031 | return needed_bytes; | ||
| 2032 | } | ||
| 2004 | 2033 | ||
| 2005 | DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0, | 2034 | DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0, |
| 2006 | doc: /* Return a new bool-vector of length LENGTH, using INIT for each element. | 2035 | doc: /* Return a new bool-vector of length LENGTH, using INIT for each element. |
| @@ -2009,37 +2038,43 @@ LENGTH must be a number. INIT matters only in whether it is t or nil. */) | |||
| 2009 | { | 2038 | { |
| 2010 | register Lisp_Object val; | 2039 | register Lisp_Object val; |
| 2011 | struct Lisp_Bool_Vector *p; | 2040 | struct Lisp_Bool_Vector *p; |
| 2012 | ptrdiff_t length_in_chars; | 2041 | ptrdiff_t exact_payload_bytes; |
| 2013 | EMACS_INT length_in_elts; | 2042 | ptrdiff_t total_payload_bytes; |
| 2014 | int bits_per_value; | 2043 | ptrdiff_t needed_elements; |
| 2015 | int extra_bool_elts = ((bool_header_size - header_size + word_size - 1) | ||
| 2016 | / word_size); | ||
| 2017 | 2044 | ||
| 2018 | CHECK_NATNUM (length); | 2045 | CHECK_NATNUM (length); |
| 2046 | if (PTRDIFF_MAX < XFASTINT (length)) | ||
| 2047 | memory_full (SIZE_MAX); | ||
| 2019 | 2048 | ||
| 2020 | bits_per_value = sizeof (EMACS_INT) * BOOL_VECTOR_BITS_PER_CHAR; | 2049 | total_payload_bytes = bool_vector_payload_bytes |
| 2050 | (XFASTINT (length), &exact_payload_bytes); | ||
| 2021 | 2051 | ||
| 2022 | length_in_elts = (XFASTINT (length) + bits_per_value - 1) / bits_per_value; | 2052 | eassert_and_assume (exact_payload_bytes <= total_payload_bytes); |
| 2053 | eassert_and_assume (0 <= exact_payload_bytes); | ||
| 2023 | 2054 | ||
| 2024 | val = Fmake_vector (make_number (length_in_elts + extra_bool_elts), Qnil); | 2055 | needed_elements = ROUNDUP ((size_t) ((bool_header_size - header_size) |
| 2056 | + total_payload_bytes), | ||
| 2057 | word_size) / word_size; | ||
| 2025 | 2058 | ||
| 2026 | /* No Lisp_Object to trace in there. */ | 2059 | p = (struct Lisp_Bool_Vector* ) allocate_vector (needed_elements); |
| 2060 | XSETVECTOR (val, p); | ||
| 2027 | XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0, 0); | 2061 | XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0, 0); |
| 2028 | 2062 | ||
| 2029 | p = XBOOL_VECTOR (val); | ||
| 2030 | p->size = XFASTINT (length); | 2063 | p->size = XFASTINT (length); |
| 2031 | 2064 | if (exact_payload_bytes) | |
| 2032 | length_in_chars = ((XFASTINT (length) + BOOL_VECTOR_BITS_PER_CHAR - 1) | ||
| 2033 | / BOOL_VECTOR_BITS_PER_CHAR); | ||
| 2034 | if (length_in_chars) | ||
| 2035 | { | 2065 | { |
| 2036 | memset (p->data, ! NILP (init) ? -1 : 0, length_in_chars); | 2066 | memset (p->data, ! NILP (init) ? -1 : 0, exact_payload_bytes); |
| 2037 | 2067 | ||
| 2038 | /* Clear any extraneous bits in the last byte. */ | 2068 | /* Clear any extraneous bits in the last byte. */ |
| 2039 | p->data[length_in_chars - 1] | 2069 | p->data[exact_payload_bytes - 1] |
| 2040 | &= (1 << ((XFASTINT (length) - 1) % BOOL_VECTOR_BITS_PER_CHAR + 1)) - 1; | 2070 | &= (1 << ((XFASTINT (length) - 1) % BOOL_VECTOR_BITS_PER_CHAR + 1)) - 1; |
| 2041 | } | 2071 | } |
| 2042 | 2072 | ||
| 2073 | /* Clear padding at the end. */ | ||
| 2074 | memset (p->data + exact_payload_bytes, | ||
| 2075 | 0, | ||
| 2076 | total_payload_bytes - exact_payload_bytes); | ||
| 2077 | |||
| 2043 | return val; | 2078 | return val; |
| 2044 | } | 2079 | } |
| 2045 | 2080 | ||
| @@ -2565,24 +2600,22 @@ enum | |||
| 2565 | roundup_size = COMMON_MULTIPLE (word_size, USE_LSB_TAG ? GCALIGNMENT : 1) | 2600 | roundup_size = COMMON_MULTIPLE (word_size, USE_LSB_TAG ? GCALIGNMENT : 1) |
| 2566 | }; | 2601 | }; |
| 2567 | 2602 | ||
| 2568 | /* ROUNDUP_SIZE must be a power of 2. */ | ||
| 2569 | verify ((roundup_size & (roundup_size - 1)) == 0); | ||
| 2570 | |||
| 2571 | /* Verify assumptions described above. */ | 2603 | /* Verify assumptions described above. */ |
| 2572 | verify ((VECTOR_BLOCK_SIZE % roundup_size) == 0); | 2604 | verify ((VECTOR_BLOCK_SIZE % roundup_size) == 0); |
| 2573 | verify (VECTOR_BLOCK_SIZE <= (1 << PSEUDOVECTOR_SIZE_BITS)); | 2605 | verify (VECTOR_BLOCK_SIZE <= (1 << PSEUDOVECTOR_SIZE_BITS)); |
| 2574 | 2606 | ||
| 2575 | /* Round up X to nearest mult-of-ROUNDUP_SIZE. */ | 2607 | /* Round up X to nearest mult-of-ROUNDUP_SIZE --- use at compile time. */ |
| 2576 | 2608 | #define vroundup_ct(x) ROUNDUP((size_t)(x), roundup_size) | |
| 2577 | #define vroundup(x) (((x) + (roundup_size - 1)) & ~(roundup_size - 1)) | 2609 | /* Round up X to nearest mult-of-ROUNDUP_SIZE --- use at runtime. */ |
| 2610 | #define vroundup(x) (assume((x) >= 0), vroundup_ct(x)) | ||
| 2578 | 2611 | ||
| 2579 | /* Rounding helps to maintain alignment constraints if USE_LSB_TAG. */ | 2612 | /* Rounding helps to maintain alignment constraints if USE_LSB_TAG. */ |
| 2580 | 2613 | ||
| 2581 | #define VECTOR_BLOCK_BYTES (VECTOR_BLOCK_SIZE - vroundup (sizeof (void *))) | 2614 | #define VECTOR_BLOCK_BYTES (VECTOR_BLOCK_SIZE - vroundup_ct (sizeof (void *))) |
| 2582 | 2615 | ||
| 2583 | /* Size of the minimal vector allocated from block. */ | 2616 | /* Size of the minimal vector allocated from block. */ |
| 2584 | 2617 | ||
| 2585 | #define VBLOCK_BYTES_MIN vroundup (header_size + sizeof (Lisp_Object)) | 2618 | #define VBLOCK_BYTES_MIN vroundup_ct (header_size + sizeof (Lisp_Object)) |
| 2586 | 2619 | ||
| 2587 | /* Size of the largest vector allocated from block. */ | 2620 | /* Size of the largest vector allocated from block. */ |
| 2588 | 2621 | ||
| @@ -2642,7 +2675,7 @@ struct large_vector | |||
| 2642 | struct large_vector *vector; | 2675 | struct large_vector *vector; |
| 2643 | #if USE_LSB_TAG | 2676 | #if USE_LSB_TAG |
| 2644 | /* We need to maintain ROUNDUP_SIZE alignment for the vector member. */ | 2677 | /* We need to maintain ROUNDUP_SIZE alignment for the vector member. */ |
| 2645 | unsigned char c[vroundup (sizeof (struct large_vector *))]; | 2678 | unsigned char c[vroundup_ct (sizeof (struct large_vector *))]; |
| 2646 | #endif | 2679 | #endif |
| 2647 | } next; | 2680 | } next; |
| 2648 | struct Lisp_Vector v; | 2681 | struct Lisp_Vector v; |
| @@ -2783,10 +2816,14 @@ vector_nbytes (struct Lisp_Vector *v) | |||
| 2783 | if (size & PSEUDOVECTOR_FLAG) | 2816 | if (size & PSEUDOVECTOR_FLAG) |
| 2784 | { | 2817 | { |
| 2785 | if (PSEUDOVECTOR_TYPEP (&v->header, PVEC_BOOL_VECTOR)) | 2818 | if (PSEUDOVECTOR_TYPEP (&v->header, PVEC_BOOL_VECTOR)) |
| 2786 | size = (bool_header_size | 2819 | { |
| 2787 | + (((struct Lisp_Bool_Vector *) v)->size | 2820 | struct Lisp_Bool_Vector *bv = (struct Lisp_Bool_Vector *) v; |
| 2788 | + BOOL_VECTOR_BITS_PER_CHAR - 1) | 2821 | ptrdiff_t payload_bytes = |
| 2789 | / BOOL_VECTOR_BITS_PER_CHAR); | 2822 | bool_vector_payload_bytes (bv->size, NULL); |
| 2823 | |||
| 2824 | eassert_and_assume (payload_bytes >= 0); | ||
| 2825 | size = bool_header_size + ROUNDUP (payload_bytes, word_size); | ||
| 2826 | } | ||
| 2790 | else | 2827 | else |
| 2791 | size = (header_size | 2828 | size = (header_size |
| 2792 | + ((size & PSEUDOVECTOR_SIZE_MASK) | 2829 | + ((size & PSEUDOVECTOR_SIZE_MASK) |
| @@ -2886,17 +2923,11 @@ sweep_vectors (void) | |||
| 2886 | total_vectors++; | 2923 | total_vectors++; |
| 2887 | if (vector->header.size & PSEUDOVECTOR_FLAG) | 2924 | if (vector->header.size & PSEUDOVECTOR_FLAG) |
| 2888 | { | 2925 | { |
| 2889 | struct Lisp_Bool_Vector *b = (struct Lisp_Bool_Vector *) vector; | ||
| 2890 | |||
| 2891 | /* All non-bool pseudovectors are small enough to be allocated | 2926 | /* All non-bool pseudovectors are small enough to be allocated |
| 2892 | from vector blocks. This code should be redesigned if some | 2927 | from vector blocks. This code should be redesigned if some |
| 2893 | pseudovector type grows beyond VBLOCK_BYTES_MAX. */ | 2928 | pseudovector type grows beyond VBLOCK_BYTES_MAX. */ |
| 2894 | eassert (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_BOOL_VECTOR)); | 2929 | eassert (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_BOOL_VECTOR)); |
| 2895 | 2930 | total_vector_slots += vector_nbytes (vector) / word_size; | |
| 2896 | total_vector_slots | ||
| 2897 | += (bool_header_size | ||
| 2898 | + ((b->size + BOOL_VECTOR_BITS_PER_CHAR - 1) | ||
| 2899 | / BOOL_VECTOR_BITS_PER_CHAR)) / word_size; | ||
| 2900 | } | 2931 | } |
| 2901 | else | 2932 | else |
| 2902 | total_vector_slots | 2933 | total_vector_slots |
diff --git a/src/casetab.c b/src/casetab.c index b6b1c99c39f..69cd784f4cc 100644 --- a/src/casetab.c +++ b/src/casetab.c | |||
| @@ -205,7 +205,7 @@ set_identity (Lisp_Object table, Lisp_Object c, Lisp_Object elt) | |||
| 205 | from = to = XINT (c); | 205 | from = to = XINT (c); |
| 206 | 206 | ||
| 207 | to++; | 207 | to++; |
| 208 | lint_assume (to <= MAX_CHAR + 1); | 208 | assume (to <= MAX_CHAR + 1); |
| 209 | for (; from < to; from++) | 209 | for (; from < to; from++) |
| 210 | CHAR_TABLE_SET (table, from, make_number (from)); | 210 | CHAR_TABLE_SET (table, from, make_number (from)); |
| 211 | } | 211 | } |
| @@ -232,7 +232,7 @@ shuffle (Lisp_Object table, Lisp_Object c, Lisp_Object elt) | |||
| 232 | from = to = XINT (c); | 232 | from = to = XINT (c); |
| 233 | 233 | ||
| 234 | to++; | 234 | to++; |
| 235 | lint_assume (to <= MAX_CHAR + 1); | 235 | assume (to <= MAX_CHAR + 1); |
| 236 | for (; from < to; from++) | 236 | for (; from < to; from++) |
| 237 | { | 237 | { |
| 238 | Lisp_Object tem = Faref (table, elt); | 238 | Lisp_Object tem = Faref (table, elt); |
diff --git a/src/composite.c b/src/composite.c index ee4195572a5..47cac715086 100644 --- a/src/composite.c +++ b/src/composite.c | |||
| @@ -674,7 +674,7 @@ composition_gstring_put_cache (Lisp_Object gstring, ptrdiff_t len) | |||
| 674 | len = j; | 674 | len = j; |
| 675 | } | 675 | } |
| 676 | 676 | ||
| 677 | lint_assume (len <= TYPE_MAXIMUM (ptrdiff_t) - 2); | 677 | assume (len <= TYPE_MAXIMUM (ptrdiff_t) - 2); |
| 678 | copy = Fmake_vector (make_number (len + 2), Qnil); | 678 | copy = Fmake_vector (make_number (len + 2), Qnil); |
| 679 | LGSTRING_SET_HEADER (copy, Fcopy_sequence (header)); | 679 | LGSTRING_SET_HEADER (copy, Fcopy_sequence (header)); |
| 680 | for (i = 0; i < len; i++) | 680 | for (i = 0; i < len; i++) |
diff --git a/src/conf_post.h b/src/conf_post.h index 30a4a5a9422..5f6cf0eca37 100644 --- a/src/conf_post.h +++ b/src/conf_post.h | |||
| @@ -248,16 +248,24 @@ extern void _DebPrint (const char *fmt, ...); | |||
| 248 | # define FLEXIBLE_ARRAY_MEMBER 1 | 248 | # define FLEXIBLE_ARRAY_MEMBER 1 |
| 249 | #endif | 249 | #endif |
| 250 | 250 | ||
| 251 | /* assume(cond) tells the compiler (and lint) that a certain condition | ||
| 252 | * will always hold, and that it should optimize (or check) accordingly. */ | ||
| 253 | #if defined lint | ||
| 254 | # define assume(cond) ((cond) ? (void) 0 : abort ()) | ||
| 255 | #elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) || __GNUC__ > 4 | ||
| 256 | # define assume(cond) ((x) || (__builtin_unreachable(), 0)) | ||
| 257 | #elif defined __MSC_VER | ||
| 258 | # define assume(cond) __assume ((cond)) | ||
| 259 | #else | ||
| 260 | # define assume(cond) (0 && (cond)) | ||
| 261 | #endif | ||
| 262 | |||
| 251 | /* Use this to suppress gcc's `...may be used before initialized' warnings. */ | 263 | /* Use this to suppress gcc's `...may be used before initialized' warnings. */ |
| 252 | #ifdef lint | 264 | #ifdef lint |
| 253 | /* Use CODE only if lint checking is in effect. */ | 265 | /* Use CODE only if lint checking is in effect. */ |
| 254 | # define IF_LINT(Code) Code | 266 | # define IF_LINT(Code) Code |
| 255 | /* Assume that the expression COND is true. This differs in intent | ||
| 256 | from 'assert', as it is a message from the programmer to the compiler. */ | ||
| 257 | # define lint_assume(cond) ((cond) ? (void) 0 : abort ()) | ||
| 258 | #else | 267 | #else |
| 259 | # define IF_LINT(Code) /* empty */ | 268 | # define IF_LINT(Code) /* empty */ |
| 260 | # define lint_assume(cond) ((void) (0 && (cond))) | ||
| 261 | #endif | 269 | #endif |
| 262 | 270 | ||
| 263 | /* conf_post.h ends here */ | 271 | /* conf_post.h ends here */ |
diff --git a/src/data.c b/src/data.c index 51b0266eca1..5a05e0652ad 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -54,6 +54,7 @@ Lisp_Object Qintegerp, Qwholenump, Qsymbolp, Qlistp, Qconsp; | |||
| 54 | static Lisp_Object Qnatnump; | 54 | static Lisp_Object Qnatnump; |
| 55 | Lisp_Object Qstringp, Qarrayp, Qsequencep, Qbufferp; | 55 | Lisp_Object Qstringp, Qarrayp, Qsequencep, Qbufferp; |
| 56 | Lisp_Object Qchar_or_string_p, Qmarkerp, Qinteger_or_marker_p, Qvectorp; | 56 | Lisp_Object Qchar_or_string_p, Qmarkerp, Qinteger_or_marker_p, Qvectorp; |
| 57 | Lisp_Object Qbool_vector_p; | ||
| 57 | Lisp_Object Qbuffer_or_string_p; | 58 | Lisp_Object Qbuffer_or_string_p; |
| 58 | static Lisp_Object Qkeywordp, Qboundp; | 59 | static Lisp_Object Qkeywordp, Qboundp; |
| 59 | Lisp_Object Qfboundp; | 60 | Lisp_Object Qfboundp; |
| @@ -2956,6 +2957,457 @@ lowercase l) for small endian machines. */) | |||
| 2956 | return make_number (order); | 2957 | return make_number (order); |
| 2957 | } | 2958 | } |
| 2958 | 2959 | ||
| 2960 | /* Because we round up the bool vector allocate size to word_size | ||
| 2961 | units, we can safely read past the "end" of the vector in the | ||
| 2962 | operations below. These extra bits are always zero. Also, we | ||
| 2963 | always allocate bool vectors with at least one size_t of storage so | ||
| 2964 | that we don't have to special-case empty bit vectors. */ | ||
| 2965 | |||
| 2966 | static inline | ||
| 2967 | size_t | ||
| 2968 | bool_vector_spare_mask (ptrdiff_t nr_bits) | ||
| 2969 | { | ||
| 2970 | eassert_and_assume (nr_bits > 0); | ||
| 2971 | return (((size_t) 1) << (nr_bits % BITS_PER_SIZE_T)) - 1; | ||
| 2972 | } | ||
| 2973 | |||
| 2974 | #if __MSC_VER >= 1500 && (defined _M_IX86 || defined _M_X64) | ||
| 2975 | # define USE_MSC_POPCOUNT | ||
| 2976 | #elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) | ||
| 2977 | # define USE_GCC_POPCOUNT | ||
| 2978 | #else | ||
| 2979 | # define NEED_GENERIC_POPCOUNT | ||
| 2980 | #endif | ||
| 2981 | |||
| 2982 | #ifdef USE_MSC_POPCOUNT | ||
| 2983 | #define NEED_GENERIC_POPCOUNT | ||
| 2984 | #endif | ||
| 2985 | |||
| 2986 | #ifdef NEED_GENERIC_POPCOUNT | ||
| 2987 | static inline | ||
| 2988 | unsigned int | ||
| 2989 | popcount_size_t_generic (size_t val) | ||
| 2990 | { | ||
| 2991 | unsigned short j; | ||
| 2992 | unsigned int count = 0; | ||
| 2993 | |||
| 2994 | for (j = 0; j < BITS_PER_SIZE_T; ++j) | ||
| 2995 | count += !!((((size_t) 1) << j) & val); | ||
| 2996 | |||
| 2997 | return count; | ||
| 2998 | } | ||
| 2999 | #endif | ||
| 3000 | |||
| 3001 | #ifdef USE_MSC_POPCOUNT | ||
| 3002 | static inline | ||
| 3003 | unsigned int | ||
| 3004 | popcount_size_t_msc (size_t val) | ||
| 3005 | { | ||
| 3006 | unsigned int count; | ||
| 3007 | |||
| 3008 | #pragma intrinsic __cpuid | ||
| 3009 | /* While gcc falls back to its own generic code if the machine on | ||
| 3010 | which it's running doesn't support popcount, we need to perform the | ||
| 3011 | detection and fallback ourselves when compiling with Microsoft's | ||
| 3012 | compiler. */ | ||
| 3013 | |||
| 3014 | static enum { | ||
| 3015 | popcount_unknown_support, | ||
| 3016 | popcount_use_generic, | ||
| 3017 | popcount_use_intrinsic | ||
| 3018 | } popcount_state; | ||
| 3019 | |||
| 3020 | if (popcount_state == popcount_unknown_support) | ||
| 3021 | { | ||
| 3022 | int cpu_info[4]; | ||
| 3023 | __cpuid (cpu_info, 1); | ||
| 3024 | if (cpu_info[2] & (1<<23)) /* See MSDN. */ | ||
| 3025 | popcount_state = popcount_use_intrinsic; | ||
| 3026 | else | ||
| 3027 | popcount_state = popcount_use_generic; | ||
| 3028 | } | ||
| 3029 | |||
| 3030 | if (popcount_state == popcount_use_intrinsic) | ||
| 3031 | { | ||
| 3032 | # if BITS_PER_SIZE_T == 64 | ||
| 3033 | # pragma intrinsic __popcnt64 | ||
| 3034 | count = __popcnt64 (val); | ||
| 3035 | # else | ||
| 3036 | # pragma intrinsic __popcnt | ||
| 3037 | count = __popcnt (val); | ||
| 3038 | # endif | ||
| 3039 | } | ||
| 3040 | else | ||
| 3041 | count = popcount_size_t_generic (val); | ||
| 3042 | |||
| 3043 | return count; | ||
| 3044 | } | ||
| 3045 | #endif /* USE_MSC_POPCOUNT */ | ||
| 3046 | |||
| 3047 | #ifdef USE_GCC_POPCOUNT | ||
| 3048 | static inline | ||
| 3049 | unsigned int | ||
| 3050 | popcount_size_t_gcc (size_t val) | ||
| 3051 | { | ||
| 3052 | # if BITS_PER_SIZE_T == 64 | ||
| 3053 | return __builtin_popcountll (val); | ||
| 3054 | # else | ||
| 3055 | return __builtin_popcount (val); | ||
| 3056 | # endif | ||
| 3057 | } | ||
| 3058 | #endif /* USE_GCC_POPCOUNT */ | ||
| 3059 | |||
| 3060 | static inline | ||
| 3061 | unsigned int | ||
| 3062 | popcount_size_t(size_t val) | ||
| 3063 | { | ||
| 3064 | #if defined USE_MSC_POPCOUNT | ||
| 3065 | return popcount_size_t_msc (val); | ||
| 3066 | #elif defined USE_GCC_POPCOUNT | ||
| 3067 | return popcount_size_t_gcc (val); | ||
| 3068 | #else | ||
| 3069 | return popcount_size_t_generic (val); | ||
| 3070 | #endif | ||
| 3071 | } | ||
| 3072 | |||
| 3073 | enum bool_vector_op { bool_vector_exclusive_or, | ||
| 3074 | bool_vector_union, | ||
| 3075 | bool_vector_intersection, | ||
| 3076 | bool_vector_set_difference, | ||
| 3077 | bool_vector_subsetp }; | ||
| 3078 | |||
| 3079 | static inline | ||
| 3080 | Lisp_Object | ||
| 3081 | bool_vector_binop_driver (Lisp_Object op1, | ||
| 3082 | Lisp_Object op2, | ||
| 3083 | Lisp_Object dest, | ||
| 3084 | enum bool_vector_op op) | ||
| 3085 | { | ||
| 3086 | EMACS_INT nr_bits; | ||
| 3087 | size_t *adata, *bdata, *cdata; | ||
| 3088 | ptrdiff_t i; | ||
| 3089 | size_t changed = 0; | ||
| 3090 | size_t mword; | ||
| 3091 | ptrdiff_t nr_words; | ||
| 3092 | |||
| 3093 | CHECK_BOOL_VECTOR (op1); | ||
| 3094 | CHECK_BOOL_VECTOR (op2); | ||
| 3095 | |||
| 3096 | nr_bits = min (XBOOL_VECTOR (op1)->size, | ||
| 3097 | XBOOL_VECTOR (op2)->size); | ||
| 3098 | |||
| 3099 | if (NILP (dest)) | ||
| 3100 | { | ||
| 3101 | dest = Fmake_bool_vector (make_number (nr_bits), Qnil); | ||
| 3102 | changed = 1; | ||
| 3103 | } | ||
| 3104 | else | ||
| 3105 | { | ||
| 3106 | CHECK_BOOL_VECTOR (dest); | ||
| 3107 | nr_bits = min (nr_bits, XBOOL_VECTOR (dest)->size); | ||
| 3108 | } | ||
| 3109 | |||
| 3110 | eassert_and_assume (nr_bits >= 0); | ||
| 3111 | nr_words = ROUNDUP(nr_bits, BITS_PER_SIZE_T) / BITS_PER_SIZE_T; | ||
| 3112 | |||
| 3113 | adata = (size_t*) XBOOL_VECTOR (dest)->data; | ||
| 3114 | bdata = (size_t*) XBOOL_VECTOR (op1)->data; | ||
| 3115 | cdata = (size_t*) XBOOL_VECTOR (op2)->data; | ||
| 3116 | i = 0; | ||
| 3117 | do | ||
| 3118 | { | ||
| 3119 | if (op == bool_vector_exclusive_or) | ||
| 3120 | mword = bdata[i] ^ cdata[i]; | ||
| 3121 | else if (op == bool_vector_union || op == bool_vector_subsetp) | ||
| 3122 | mword = bdata[i] | cdata[i]; | ||
| 3123 | else if (op == bool_vector_intersection) | ||
| 3124 | mword = bdata[i] & cdata[i]; | ||
| 3125 | else if (op == bool_vector_set_difference) | ||
| 3126 | mword = bdata[i] &~ cdata[i]; | ||
| 3127 | else | ||
| 3128 | abort (); | ||
| 3129 | |||
| 3130 | changed |= adata[i] ^ mword; | ||
| 3131 | |||
| 3132 | if (op != bool_vector_subsetp) | ||
| 3133 | adata[i] = mword; | ||
| 3134 | |||
| 3135 | i += 1; | ||
| 3136 | } | ||
| 3137 | while (i < nr_words); | ||
| 3138 | return changed ? dest : Qnil; | ||
| 3139 | } | ||
| 3140 | |||
| 3141 | /* Compute the number of trailing zero bits in val. If val is zero, | ||
| 3142 | return the number of bits in val. */ | ||
| 3143 | static inline | ||
| 3144 | unsigned int | ||
| 3145 | count_trailing_zero_bits (size_t val) | ||
| 3146 | { | ||
| 3147 | if (val == 0) | ||
| 3148 | return CHAR_BIT * sizeof (val); | ||
| 3149 | |||
| 3150 | #if defined USE_GCC_POPCOUNT && BITS_PER_SIZE_T == 64 | ||
| 3151 | return __builtin_ctzll (val); | ||
| 3152 | #elif defined USE_GCC_POPCOUNT && BITS_PER_SIZE_T == 32 | ||
| 3153 | return __builtin_ctz (val); | ||
| 3154 | #elif __MSC_VER && BITS_PER_SIZE_T == 64 | ||
| 3155 | # pragma intrinsic _BitScanForward64 | ||
| 3156 | { | ||
| 3157 | /* No support test needed: support since 386. */ | ||
| 3158 | unsigned long result; | ||
| 3159 | _BitScanForward64 (&result, val); | ||
| 3160 | return (unsigned int) result; | ||
| 3161 | } | ||
| 3162 | #elif __MSC_VER && BITS_PER_SIZE_T == 32 | ||
| 3163 | # pragma intrinsic _BitScanForward | ||
| 3164 | { | ||
| 3165 | /* No support test needed: support since 386. */ | ||
| 3166 | unsigned long result; | ||
| 3167 | _BitScanForward (&result, val); | ||
| 3168 | return (unsigned int) result; | ||
| 3169 | } | ||
| 3170 | #else | ||
| 3171 | { | ||
| 3172 | unsigned int count; | ||
| 3173 | count = 0; | ||
| 3174 | for(val = ~val; val & 1; val >>= 1) | ||
| 3175 | ++count; | ||
| 3176 | |||
| 3177 | return count; | ||
| 3178 | } | ||
| 3179 | #endif | ||
| 3180 | } | ||
| 3181 | |||
| 3182 | static inline | ||
| 3183 | size_t | ||
| 3184 | size_t_to_host_endian (size_t val) | ||
| 3185 | { | ||
| 3186 | #ifdef WORDS_BIGENDIAN | ||
| 3187 | # if BITS_PER_SIZE_T == 64 | ||
| 3188 | return swap64 (val); | ||
| 3189 | # else | ||
| 3190 | return swap32 (val); | ||
| 3191 | # endif | ||
| 3192 | #else | ||
| 3193 | return val; | ||
| 3194 | #endif | ||
| 3195 | } | ||
| 3196 | |||
| 3197 | DEFUN ("bool-vector-exclusive-or", Fbool_vector_exclusive_or, | ||
| 3198 | Sbool_vector_exclusive_or, 2, 3, 0, | ||
| 3199 | doc: /* Compute C = A ^ B, bitwise exclusive or. | ||
| 3200 | A, B, and C must be bool vectors. If C is nil, allocate a new bool | ||
| 3201 | vector in which to store the result. Return the destination vector if | ||
| 3202 | it changed or nil otherwise. */ | ||
| 3203 | ) | ||
| 3204 | (Lisp_Object a, Lisp_Object b, Lisp_Object c) | ||
| 3205 | { | ||
| 3206 | return bool_vector_binop_driver (a, b, c, bool_vector_exclusive_or); | ||
| 3207 | } | ||
| 3208 | |||
| 3209 | DEFUN ("bool-vector-union", Fbool_vector_union, | ||
| 3210 | Sbool_vector_union, 2, 3, 0, | ||
| 3211 | doc: /* Compute C = A | B, bitwise or. | ||
| 3212 | A, B, and C must be bool vectors. If C is nil, allocate a new bool | ||
| 3213 | vector in which to store the result. Return the destination vector if | ||
| 3214 | it changed or nil otherwise. */) | ||
| 3215 | (Lisp_Object a, Lisp_Object b, Lisp_Object c) | ||
| 3216 | { | ||
| 3217 | return bool_vector_binop_driver (a, b, c, bool_vector_union); | ||
| 3218 | } | ||
| 3219 | |||
| 3220 | DEFUN ("bool-vector-intersection", Fbool_vector_intersection, | ||
| 3221 | Sbool_vector_intersection, 2, 3, 0, | ||
| 3222 | doc: /* Compute C = A & B, bitwise and. | ||
| 3223 | A, B, and C must be bool vectors. If C is nil, allocate a new bool | ||
| 3224 | vector in which to store the result. Return the destination vector if | ||
| 3225 | it changed or nil otherwise. */) | ||
| 3226 | (Lisp_Object a, Lisp_Object b, Lisp_Object c) | ||
| 3227 | { | ||
| 3228 | return bool_vector_binop_driver (a, b, c, bool_vector_intersection); | ||
| 3229 | } | ||
| 3230 | |||
| 3231 | DEFUN ("bool-vector-set-difference", Fbool_vector_set_difference, | ||
| 3232 | Sbool_vector_set_difference, 2, 3, 0, | ||
| 3233 | doc: /* Compute C = A &~ B, set difference. | ||
| 3234 | A, B, and C must be bool vectors. If C is nil, allocate a new bool | ||
| 3235 | vector in which to store the result. Return the destination vector if | ||
| 3236 | it changed or nil otherwise. */) | ||
| 3237 | (Lisp_Object a, Lisp_Object b, Lisp_Object c) | ||
| 3238 | { | ||
| 3239 | return bool_vector_binop_driver (a, b, c, bool_vector_set_difference); | ||
| 3240 | } | ||
| 3241 | |||
| 3242 | DEFUN ("bool-vector-subsetp", Fbool_vector_subsetp, | ||
| 3243 | Sbool_vector_subsetp, 2, 2, 0, | ||
| 3244 | doc: ) | ||
| 3245 | (Lisp_Object a, Lisp_Object b) | ||
| 3246 | { | ||
| 3247 | /* Like bool_vector_union, but doesn't modify b. */ | ||
| 3248 | return bool_vector_binop_driver (b, a, b, bool_vector_subsetp); | ||
| 3249 | } | ||
| 3250 | |||
| 3251 | DEFUN ("bool-vector-not", Fbool_vector_not, | ||
| 3252 | Sbool_vector_not, 1, 2, 0, | ||
| 3253 | doc: /* Compute B = ~A. | ||
| 3254 | B must be a bool vector. A must be a bool vector or nil. | ||
| 3255 | If A is nil, allocate a new bool vector in which to store the result. | ||
| 3256 | Return the destination vector. */) | ||
| 3257 | (Lisp_Object a, Lisp_Object b) | ||
| 3258 | { | ||
| 3259 | EMACS_INT nr_bits; | ||
| 3260 | size_t *bdata, *adata; | ||
| 3261 | ptrdiff_t i; | ||
| 3262 | size_t mword; | ||
| 3263 | |||
| 3264 | CHECK_BOOL_VECTOR (a); | ||
| 3265 | nr_bits = XBOOL_VECTOR (a)->size; | ||
| 3266 | |||
| 3267 | if (NILP (b)) | ||
| 3268 | b = Fmake_bool_vector (make_number (nr_bits), Qnil); | ||
| 3269 | else | ||
| 3270 | { | ||
| 3271 | CHECK_BOOL_VECTOR (b); | ||
| 3272 | nr_bits = min (nr_bits, XBOOL_VECTOR (b)->size); | ||
| 3273 | } | ||
| 3274 | |||
| 3275 | bdata = (size_t*) XBOOL_VECTOR (b)->data; | ||
| 3276 | adata = (size_t*) XBOOL_VECTOR (a)->data; | ||
| 3277 | i = 0; | ||
| 3278 | |||
| 3279 | eassert_and_assume (nr_bits >= 0); | ||
| 3280 | |||
| 3281 | while (i < nr_bits / BITS_PER_SIZE_T) | ||
| 3282 | { | ||
| 3283 | bdata[i] = ~adata[i]; | ||
| 3284 | i += 1; | ||
| 3285 | } | ||
| 3286 | |||
| 3287 | if (nr_bits % BITS_PER_SIZE_T) | ||
| 3288 | { | ||
| 3289 | mword = size_t_to_host_endian (adata[i]); | ||
| 3290 | mword = ~mword; | ||
| 3291 | mword &= bool_vector_spare_mask (nr_bits); | ||
| 3292 | bdata[i] = size_t_to_host_endian (mword); | ||
| 3293 | } | ||
| 3294 | |||
| 3295 | return b; | ||
| 3296 | } | ||
| 3297 | |||
| 3298 | DEFUN ("bool-vector-count-matches", Fbool_vector_count_matches, | ||
| 3299 | Sbool_vector_count_matches, 2, 2, 0, | ||
| 3300 | doc: /* Count how many elements in A equal B. | ||
| 3301 | A must be a bool vector. B is a generalized bool. */) | ||
| 3302 | (Lisp_Object a, Lisp_Object b) | ||
| 3303 | { | ||
| 3304 | ptrdiff_t count; | ||
| 3305 | EMACS_INT nr_bits; | ||
| 3306 | size_t *adata; | ||
| 3307 | size_t match; | ||
| 3308 | ptrdiff_t i; | ||
| 3309 | |||
| 3310 | CHECK_BOOL_VECTOR (a); | ||
| 3311 | |||
| 3312 | nr_bits = XBOOL_VECTOR (a)->size; | ||
| 3313 | count = 0; | ||
| 3314 | match = NILP (b) ? (size_t) -1 : 0; | ||
| 3315 | adata = (size_t*) XBOOL_VECTOR (a)->data; | ||
| 3316 | |||
| 3317 | eassert_and_assume (nr_bits >= 0); | ||
| 3318 | |||
| 3319 | for(i = 0; i < nr_bits / BITS_PER_SIZE_T; ++i) | ||
| 3320 | count += popcount_size_t (adata[i] ^ match); | ||
| 3321 | |||
| 3322 | /* Mask out trailing parts of final mword. */ | ||
| 3323 | if (nr_bits % BITS_PER_SIZE_T) | ||
| 3324 | { | ||
| 3325 | size_t mword = adata[i] ^ match; | ||
| 3326 | mword = size_t_to_host_endian (mword); | ||
| 3327 | count += popcount_size_t (mword & bool_vector_spare_mask (nr_bits)); | ||
| 3328 | } | ||
| 3329 | |||
| 3330 | return make_number (count); | ||
| 3331 | } | ||
| 3332 | |||
| 3333 | DEFUN ("bool-vector-count-matches-at", | ||
| 3334 | Fbool_vector_count_matches_at, | ||
| 3335 | Sbool_vector_count_matches_at, 3, 3, 0, | ||
| 3336 | doc: /* Count how many consecutive elements in A equal B at i. | ||
| 3337 | A must be a bool vector. B is a generalized boolean. i is an | ||
| 3338 | index into the vector.*/) | ||
| 3339 | (Lisp_Object a, Lisp_Object b, Lisp_Object i) | ||
| 3340 | { | ||
| 3341 | ptrdiff_t count; | ||
| 3342 | EMACS_INT nr_bits; | ||
| 3343 | ptrdiff_t offset; | ||
| 3344 | size_t *adata; | ||
| 3345 | size_t twiddle; | ||
| 3346 | size_t mword; /* Machine word. */ | ||
| 3347 | ptrdiff_t pos; | ||
| 3348 | ptrdiff_t nr_words; | ||
| 3349 | |||
| 3350 | CHECK_BOOL_VECTOR (a); | ||
| 3351 | CHECK_NATNUM (i); | ||
| 3352 | |||
| 3353 | nr_bits = XBOOL_VECTOR (a)->size; | ||
| 3354 | if (XFASTINT (i) > nr_bits) /* Allow one past the end for convenience */ | ||
| 3355 | args_out_of_range (a, i); | ||
| 3356 | |||
| 3357 | adata = (size_t*) XBOOL_VECTOR (a)->data; | ||
| 3358 | |||
| 3359 | assume (nr_bits >= 0); | ||
| 3360 | nr_words = ROUNDUP (nr_bits, BITS_PER_SIZE_T) / BITS_PER_SIZE_T; | ||
| 3361 | |||
| 3362 | pos = XFASTINT (i) / BITS_PER_SIZE_T; | ||
| 3363 | offset = XFASTINT (i) % BITS_PER_SIZE_T; | ||
| 3364 | count = 0; | ||
| 3365 | |||
| 3366 | /* By XORing with twiddle, we transform the problem of "count | ||
| 3367 | consecutive equal values" into "count the zero bits". The latter | ||
| 3368 | operation usually has hardware support. */ | ||
| 3369 | twiddle = NILP (b) ? 0 : (size_t) -1; | ||
| 3370 | |||
| 3371 | /* Scan the remainder of the mword at the current offset. */ | ||
| 3372 | if (pos < nr_words && offset != 0) | ||
| 3373 | { | ||
| 3374 | mword = size_t_to_host_endian (adata[pos]); | ||
| 3375 | mword ^= twiddle; | ||
| 3376 | mword >>= offset; | ||
| 3377 | count = count_trailing_zero_bits (mword); | ||
| 3378 | count = min (count, BITS_PER_SIZE_T - offset); | ||
| 3379 | pos += 1; | ||
| 3380 | if (count + offset < BITS_PER_SIZE_T) | ||
| 3381 | return make_number (count); | ||
| 3382 | } | ||
| 3383 | |||
| 3384 | /* Scan whole words until we either reach the end of the vector or | ||
| 3385 | find an mword that doesn't completely match. twiddle is | ||
| 3386 | endian-independent. */ | ||
| 3387 | while (pos < nr_words && adata[pos] == twiddle) | ||
| 3388 | { | ||
| 3389 | count += BITS_PER_SIZE_T; | ||
| 3390 | ++pos; | ||
| 3391 | } | ||
| 3392 | |||
| 3393 | if (pos < nr_words) | ||
| 3394 | { | ||
| 3395 | /* If we stopped because of a mismatch, see how many bits match | ||
| 3396 | in the current mword. */ | ||
| 3397 | mword = size_t_to_host_endian (adata[pos]); | ||
| 3398 | mword ^= twiddle; | ||
| 3399 | count += count_trailing_zero_bits (mword); | ||
| 3400 | } | ||
| 3401 | else if (nr_bits % BITS_PER_SIZE_T != 0) | ||
| 3402 | { | ||
| 3403 | /* If we hit the end, we might have overshot our count. Reduce | ||
| 3404 | the total by the number of spare bits at the end of the | ||
| 3405 | vector. */ | ||
| 3406 | count -= BITS_PER_SIZE_T - nr_bits % BITS_PER_SIZE_T; | ||
| 3407 | } | ||
| 3408 | |||
| 3409 | return make_number (count); | ||
| 3410 | } | ||
| 2959 | 3411 | ||
| 2960 | 3412 | ||
| 2961 | void | 3413 | void |
| @@ -3005,6 +3457,7 @@ syms_of_data (void) | |||
| 3005 | DEFSYM (Qsequencep, "sequencep"); | 3457 | DEFSYM (Qsequencep, "sequencep"); |
| 3006 | DEFSYM (Qbufferp, "bufferp"); | 3458 | DEFSYM (Qbufferp, "bufferp"); |
| 3007 | DEFSYM (Qvectorp, "vectorp"); | 3459 | DEFSYM (Qvectorp, "vectorp"); |
| 3460 | DEFSYM (Qbool_vector_p, "bool-vector-p"); | ||
| 3008 | DEFSYM (Qchar_or_string_p, "char-or-string-p"); | 3461 | DEFSYM (Qchar_or_string_p, "char-or-string-p"); |
| 3009 | DEFSYM (Qmarkerp, "markerp"); | 3462 | DEFSYM (Qmarkerp, "markerp"); |
| 3010 | DEFSYM (Qbuffer_or_string_p, "buffer-or-string-p"); | 3463 | DEFSYM (Qbuffer_or_string_p, "buffer-or-string-p"); |
| @@ -3222,6 +3675,15 @@ syms_of_data (void) | |||
| 3222 | defsubr (&Ssubr_arity); | 3675 | defsubr (&Ssubr_arity); |
| 3223 | defsubr (&Ssubr_name); | 3676 | defsubr (&Ssubr_name); |
| 3224 | 3677 | ||
| 3678 | defsubr (&Sbool_vector_exclusive_or); | ||
| 3679 | defsubr (&Sbool_vector_union); | ||
| 3680 | defsubr (&Sbool_vector_intersection); | ||
| 3681 | defsubr (&Sbool_vector_set_difference); | ||
| 3682 | defsubr (&Sbool_vector_not); | ||
| 3683 | defsubr (&Sbool_vector_subsetp); | ||
| 3684 | defsubr (&Sbool_vector_count_matches); | ||
| 3685 | defsubr (&Sbool_vector_count_matches_at); | ||
| 3686 | |||
| 3225 | set_symbol_function (Qwholenump, XSYMBOL (Qnatnump)->function); | 3687 | set_symbol_function (Qwholenump, XSYMBOL (Qnatnump)->function); |
| 3226 | 3688 | ||
| 3227 | DEFVAR_LISP ("most-positive-fixnum", Vmost_positive_fixnum, | 3689 | DEFVAR_LISP ("most-positive-fixnum", Vmost_positive_fixnum, |
diff --git a/src/dispnew.c b/src/dispnew.c index 5bdc84f1b1d..ed7349a4507 100644 --- a/src/dispnew.c +++ b/src/dispnew.c | |||
| @@ -4451,7 +4451,7 @@ update_frame_1 (struct frame *f, bool force_p, bool inhibit_id_p) | |||
| 4451 | } | 4451 | } |
| 4452 | } | 4452 | } |
| 4453 | 4453 | ||
| 4454 | lint_assume (0 <= FRAME_LINES (f)); | 4454 | assume (0 <= FRAME_LINES (f)); |
| 4455 | pause_p = 0 < i && i < FRAME_LINES (f) - 1; | 4455 | pause_p = 0 < i && i < FRAME_LINES (f) - 1; |
| 4456 | 4456 | ||
| 4457 | /* Now just clean up termcap drivers and set cursor, etc. */ | 4457 | /* Now just clean up termcap drivers and set cursor, etc. */ |
diff --git a/src/ftfont.c b/src/ftfont.c index 3636f86f5c4..4e58d83fd64 100644 --- a/src/ftfont.c +++ b/src/ftfont.c | |||
| @@ -2425,7 +2425,7 @@ ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font, | |||
| 2425 | } | 2425 | } |
| 2426 | 2426 | ||
| 2427 | len = i; | 2427 | len = i; |
| 2428 | lint_assume (len <= STRING_BYTES_BOUND); | 2428 | assume (len <= STRING_BYTES_BOUND); |
| 2429 | 2429 | ||
| 2430 | if (with_variation_selector) | 2430 | if (with_variation_selector) |
| 2431 | { | 2431 | { |
diff --git a/src/image.c b/src/image.c index e3159533664..e429830cc96 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -7523,7 +7523,7 @@ gif_load (struct frame *f, struct image *img) | |||
| 7523 | { | 7523 | { |
| 7524 | while (subimg_height <= row) | 7524 | while (subimg_height <= row) |
| 7525 | { | 7525 | { |
| 7526 | lint_assume (pass < 3); | 7526 | assume (pass < 3); |
| 7527 | row = interlace_start[++pass]; | 7527 | row = interlace_start[++pass]; |
| 7528 | } | 7528 | } |
| 7529 | 7529 | ||
diff --git a/src/intervals.c b/src/intervals.c index 66b486e1422..69a33867283 100644 --- a/src/intervals.c +++ b/src/intervals.c | |||
| @@ -1405,7 +1405,7 @@ offset_intervals (struct buffer *buffer, ptrdiff_t start, ptrdiff_t length) | |||
| 1405 | start, length); | 1405 | start, length); |
| 1406 | else | 1406 | else |
| 1407 | { | 1407 | { |
| 1408 | lint_assume (- TYPE_MAXIMUM (ptrdiff_t) <= length); | 1408 | assume (- TYPE_MAXIMUM (ptrdiff_t) <= length); |
| 1409 | adjust_intervals_for_deletion (buffer, start, -length); | 1409 | adjust_intervals_for_deletion (buffer, start, -length); |
| 1410 | } | 1410 | } |
| 1411 | } | 1411 | } |
diff --git a/src/lisp.h b/src/lisp.h index bd09cab5a75..0fffea57578 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -131,6 +131,13 @@ extern bool suppress_checking EXTERNALLY_VISIBLE; | |||
| 131 | ? (void) 0 \ | 131 | ? (void) 0 \ |
| 132 | : die (# cond, __FILE__, __LINE__)) | 132 | : die (# cond, __FILE__, __LINE__)) |
| 133 | #endif /* ENABLE_CHECKING */ | 133 | #endif /* ENABLE_CHECKING */ |
| 134 | |||
| 135 | /* When checking is enabled, identical to eassert. When checking is | ||
| 136 | * disabled, instruct the compiler (when the compiler has such | ||
| 137 | * capability) to assume that cond is true and optimize | ||
| 138 | * accordingly. */ | ||
| 139 | #define eassert_and_assume(cond) (eassert (cond), assume (cond)) | ||
| 140 | |||
| 134 | 141 | ||
| 135 | /* Use the configure flag --enable-check-lisp-object-type to make | 142 | /* Use the configure flag --enable-check-lisp-object-type to make |
| 136 | Lisp_Object use a struct type instead of the default int. The flag | 143 | Lisp_Object use a struct type instead of the default int. The flag |
| @@ -730,6 +737,7 @@ extern int char_table_translate (Lisp_Object, int); | |||
| 730 | extern Lisp_Object Qarrayp, Qbufferp, Qbuffer_or_string_p, Qchar_table_p; | 737 | extern Lisp_Object Qarrayp, Qbufferp, Qbuffer_or_string_p, Qchar_table_p; |
| 731 | extern Lisp_Object Qconsp, Qfloatp, Qintegerp, Qlambda, Qlistp, Qmarkerp, Qnil; | 738 | extern Lisp_Object Qconsp, Qfloatp, Qintegerp, Qlambda, Qlistp, Qmarkerp, Qnil; |
| 732 | extern Lisp_Object Qnumberp, Qstringp, Qsymbolp, Qvectorp; | 739 | extern Lisp_Object Qnumberp, Qstringp, Qsymbolp, Qvectorp; |
| 740 | extern Lisp_Object Qbool_vector_p; | ||
| 733 | extern Lisp_Object Qvector_or_char_table_p, Qwholenump; | 741 | extern Lisp_Object Qvector_or_char_table_p, Qwholenump; |
| 734 | extern Lisp_Object Qwindow; | 742 | extern Lisp_Object Qwindow; |
| 735 | extern Lisp_Object Ffboundp (Lisp_Object); | 743 | extern Lisp_Object Ffboundp (Lisp_Object); |
| @@ -2359,6 +2367,11 @@ CHECK_VECTOR (Lisp_Object x) | |||
| 2359 | CHECK_TYPE (VECTORP (x), Qvectorp, x); | 2367 | CHECK_TYPE (VECTORP (x), Qvectorp, x); |
| 2360 | } | 2368 | } |
| 2361 | INLINE void | 2369 | INLINE void |
| 2370 | CHECK_BOOL_VECTOR (Lisp_Object x) | ||
| 2371 | { | ||
| 2372 | CHECK_TYPE (BOOL_VECTOR_P (x), Qbool_vector_p, x); | ||
| 2373 | } | ||
| 2374 | INLINE void | ||
| 2362 | CHECK_VECTOR_OR_STRING (Lisp_Object x) | 2375 | CHECK_VECTOR_OR_STRING (Lisp_Object x) |
| 2363 | { | 2376 | { |
| 2364 | CHECK_TYPE (VECTORP (x) || STRINGP (x), Qarrayp, x); | 2377 | CHECK_TYPE (VECTORP (x) || STRINGP (x), Qarrayp, x); |
| @@ -4347,6 +4360,43 @@ functionp (Lisp_Object object) | |||
| 4347 | return 0; | 4360 | return 0; |
| 4348 | } | 4361 | } |
| 4349 | 4362 | ||
| 4363 | INLINE | ||
| 4364 | uint16_t | ||
| 4365 | swap16 (uint16_t val) | ||
| 4366 | { | ||
| 4367 | return (val << 8) | (val & 0xFF); | ||
| 4368 | } | ||
| 4369 | |||
| 4370 | INLINE | ||
| 4371 | uint32_t | ||
| 4372 | swap32 (uint32_t val) | ||
| 4373 | { | ||
| 4374 | uint32_t low = swap16 (val & 0xFFFF); | ||
| 4375 | uint32_t high = swap16 (val >> 16); | ||
| 4376 | return (low << 16) | high; | ||
| 4377 | } | ||
| 4378 | |||
| 4379 | #ifdef UINT64_MAX | ||
| 4380 | INLINE | ||
| 4381 | uint64_t | ||
| 4382 | swap64 (uint64_t val) | ||
| 4383 | { | ||
| 4384 | uint64_t low = swap32 (val & 0xFFFFFFFF); | ||
| 4385 | uint64_t high = swap32 (val >> 32); | ||
| 4386 | return (low << 32) | high; | ||
| 4387 | } | ||
| 4388 | #endif | ||
| 4389 | |||
| 4390 | #if ((SIZE_MAX >> 31) >> 1) & 1 | ||
| 4391 | # define BITS_PER_SIZE_T 64 | ||
| 4392 | #else | ||
| 4393 | # define BITS_PER_SIZE_T 32 | ||
| 4394 | #endif | ||
| 4395 | |||
| 4396 | /* Round x to the next multiple of y. Does not overflow. Evaluates | ||
| 4397 | arguments repeatedly. */ | ||
| 4398 | #define ROUNDUP(x,y) ((y)*((x)/(y) + ((x)%(y)!=0))) | ||
| 4399 | |||
| 4350 | INLINE_HEADER_END | 4400 | INLINE_HEADER_END |
| 4351 | 4401 | ||
| 4352 | #endif /* EMACS_LISP_H */ | 4402 | #endif /* EMACS_LISP_H */ |
diff --git a/src/macfont.m b/src/macfont.m index 2a6d219d059..ab5029743ef 100644 --- a/src/macfont.m +++ b/src/macfont.m | |||
| @@ -2817,7 +2817,7 @@ macfont_shape (Lisp_Object lgstring) | |||
| 2817 | } | 2817 | } |
| 2818 | 2818 | ||
| 2819 | len = i; | 2819 | len = i; |
| 2820 | lint_assume (len <= TYPE_MAXIMUM (EMACS_INT) - 2); | 2820 | assume (len <= TYPE_MAXIMUM (EMACS_INT) - 2); |
| 2821 | 2821 | ||
| 2822 | if (INT_MAX / 2 < len) | 2822 | if (INT_MAX / 2 < len) |
| 2823 | memory_full (SIZE_MAX); | 2823 | memory_full (SIZE_MAX); |
diff --git a/src/ralloc.c b/src/ralloc.c index 5f25ef2c320..5b7d6a512d7 100644 --- a/src/ralloc.c +++ b/src/ralloc.c | |||
| @@ -85,7 +85,7 @@ static int extra_bytes; | |||
| 85 | /* Macros for rounding. Note that rounding to any value is possible | 85 | /* Macros for rounding. Note that rounding to any value is possible |
| 86 | by changing the definition of PAGE. */ | 86 | by changing the definition of PAGE. */ |
| 87 | #define PAGE (getpagesize ()) | 87 | #define PAGE (getpagesize ()) |
| 88 | #define ROUNDUP(size) (((size_t) (size) + page_size - 1) \ | 88 | #define PAGE_ROUNDUP(size) (((size_t) (size) + page_size - 1) \ |
| 89 | & ~((size_t) (page_size - 1))) | 89 | & ~((size_t) (page_size - 1))) |
| 90 | 90 | ||
| 91 | #define MEM_ALIGN sizeof (double) | 91 | #define MEM_ALIGN sizeof (double) |
| @@ -281,7 +281,7 @@ obtain (void *address, size_t size) | |||
| 281 | Get some extra, so we can come here less often. */ | 281 | Get some extra, so we can come here less often. */ |
| 282 | 282 | ||
| 283 | get = size + extra_bytes - already_available; | 283 | get = size + extra_bytes - already_available; |
| 284 | get = (char *) ROUNDUP ((char *) last_heap->end + get) | 284 | get = (char *) PAGE_ROUNDUP ((char *) last_heap->end + get) |
| 285 | - (char *) last_heap->end; | 285 | - (char *) last_heap->end; |
| 286 | 286 | ||
| 287 | if (real_morecore (get) != last_heap->end) | 287 | if (real_morecore (get) != last_heap->end) |
| @@ -344,7 +344,7 @@ relinquish (void) | |||
| 344 | else | 344 | else |
| 345 | { | 345 | { |
| 346 | excess = ((char *) last_heap->end | 346 | excess = ((char *) last_heap->end |
| 347 | - (char *) ROUNDUP ((char *) last_heap->end - excess)); | 347 | - (char *) PAGE_ROUNDUP ((char *) last_heap->end - excess)); |
| 348 | /* If the system doesn't want that much memory back, leave | 348 | /* If the system doesn't want that much memory back, leave |
| 349 | the end of the last heap unchanged to reflect that. This | 349 | the end of the last heap unchanged to reflect that. This |
| 350 | can occur if break_value is still within the original | 350 | can occur if break_value is still within the original |
| @@ -768,9 +768,9 @@ r_alloc_sbrk (ptrdiff_t size) | |||
| 768 | not always find a space which is contiguous to the previous. */ | 768 | not always find a space which is contiguous to the previous. */ |
| 769 | void *new_bloc_start; | 769 | void *new_bloc_start; |
| 770 | heap_ptr h = first_heap; | 770 | heap_ptr h = first_heap; |
| 771 | size_t get = ROUNDUP (size); | 771 | size_t get = PAGE_ROUNDUP (size); |
| 772 | 772 | ||
| 773 | address = (void *) ROUNDUP (virtual_break_value); | 773 | address = (void *) PAGE_ROUNDUP (virtual_break_value); |
| 774 | 774 | ||
| 775 | /* Search the list upward for a heap which is large enough. */ | 775 | /* Search the list upward for a heap which is large enough. */ |
| 776 | while ((char *) h->end < (char *) MEM_ROUNDUP ((char *) address + get)) | 776 | while ((char *) h->end < (char *) MEM_ROUNDUP ((char *) address + get)) |
| @@ -778,7 +778,7 @@ r_alloc_sbrk (ptrdiff_t size) | |||
| 778 | h = h->next; | 778 | h = h->next; |
| 779 | if (h == NIL_HEAP) | 779 | if (h == NIL_HEAP) |
| 780 | break; | 780 | break; |
| 781 | address = (void *) ROUNDUP (h->start); | 781 | address = (void *) PAGE_ROUNDUP (h->start); |
| 782 | } | 782 | } |
| 783 | 783 | ||
| 784 | /* If not found, obtain more space. */ | 784 | /* If not found, obtain more space. */ |
| @@ -790,9 +790,9 @@ r_alloc_sbrk (ptrdiff_t size) | |||
| 790 | return 0; | 790 | return 0; |
| 791 | 791 | ||
| 792 | if (first_heap == last_heap) | 792 | if (first_heap == last_heap) |
| 793 | address = (void *) ROUNDUP (virtual_break_value); | 793 | address = (void *) PAGE_ROUNDUP (virtual_break_value); |
| 794 | else | 794 | else |
| 795 | address = (void *) ROUNDUP (last_heap->start); | 795 | address = (void *) PAGE_ROUNDUP (last_heap->start); |
| 796 | h = last_heap; | 796 | h = last_heap; |
| 797 | } | 797 | } |
| 798 | 798 | ||
| @@ -1054,7 +1054,7 @@ r_alloc_check (void) | |||
| 1054 | for (h = first_heap; h; h = h->next) | 1054 | for (h = first_heap; h; h = h->next) |
| 1055 | { | 1055 | { |
| 1056 | assert (h->prev == ph); | 1056 | assert (h->prev == ph); |
| 1057 | assert ((void *) ROUNDUP (h->end) == h->end); | 1057 | assert ((void *) PAGE_ROUNDUP (h->end) == h->end); |
| 1058 | #if 0 /* ??? The code in ralloc.c does not really try to ensure | 1058 | #if 0 /* ??? The code in ralloc.c does not really try to ensure |
| 1059 | the heap start has any sort of alignment. | 1059 | the heap start has any sort of alignment. |
| 1060 | Perhaps it should. */ | 1060 | Perhaps it should. */ |
| @@ -1190,7 +1190,7 @@ r_alloc_init (void) | |||
| 1190 | if (break_value == NULL) | 1190 | if (break_value == NULL) |
| 1191 | emacs_abort (); | 1191 | emacs_abort (); |
| 1192 | 1192 | ||
| 1193 | extra_bytes = ROUNDUP (50000); | 1193 | extra_bytes = PAGE_ROUNDUP (50000); |
| 1194 | #endif | 1194 | #endif |
| 1195 | 1195 | ||
| 1196 | #ifdef DOUG_LEA_MALLOC | 1196 | #ifdef DOUG_LEA_MALLOC |
| @@ -1212,7 +1212,7 @@ r_alloc_init (void) | |||
| 1212 | #endif | 1212 | #endif |
| 1213 | 1213 | ||
| 1214 | #ifndef SYSTEM_MALLOC | 1214 | #ifndef SYSTEM_MALLOC |
| 1215 | first_heap->end = (void *) ROUNDUP (first_heap->start); | 1215 | first_heap->end = (void *) PAGE_ROUNDUP (first_heap->start); |
| 1216 | 1216 | ||
| 1217 | /* The extra call to real_morecore guarantees that the end of the | 1217 | /* The extra call to real_morecore guarantees that the end of the |
| 1218 | address space is a multiple of page_size, even if page_size is | 1218 | address space is a multiple of page_size, even if page_size is |
diff --git a/src/xsettings.c b/src/xsettings.c index bdf9f2876be..8fe82fec74b 100644 --- a/src/xsettings.c +++ b/src/xsettings.c | |||
| @@ -336,9 +336,6 @@ get_prop_window (struct x_display_info *dpyinfo) | |||
| 336 | XUngrabServer (dpy); | 336 | XUngrabServer (dpy); |
| 337 | } | 337 | } |
| 338 | 338 | ||
| 339 | #define SWAP32(nr) (((nr) << 24) | (((nr) << 8) & 0xff0000) \ | ||
| 340 | | (((nr) >> 8) & 0xff00) | ((nr) >> 24)) | ||
| 341 | #define SWAP16(nr) (((nr) << 8) | ((nr) >> 8)) | ||
| 342 | #define PAD(nr) (((nr) + 3) & ~3) | 339 | #define PAD(nr) (((nr) + 3) & ~3) |
| 343 | 340 | ||
| 344 | /* Parse xsettings and extract those that deal with Xft. | 341 | /* Parse xsettings and extract those that deal with Xft. |
| @@ -408,7 +405,7 @@ parse_settings (unsigned char *prop, | |||
| 408 | 405 | ||
| 409 | if (bytes < 12) return BadLength; | 406 | if (bytes < 12) return BadLength; |
| 410 | memcpy (&n_settings, prop+8, 4); | 407 | memcpy (&n_settings, prop+8, 4); |
| 411 | if (my_bo != that_bo) n_settings = SWAP32 (n_settings); | 408 | if (my_bo != that_bo) n_settings = swap32 (n_settings); |
| 412 | bytes_parsed = 12; | 409 | bytes_parsed = 12; |
| 413 | 410 | ||
| 414 | memset (settings, 0, sizeof (*settings)); | 411 | memset (settings, 0, sizeof (*settings)); |
| @@ -430,7 +427,7 @@ parse_settings (unsigned char *prop, | |||
| 430 | 427 | ||
| 431 | memcpy (&nlen, prop+bytes_parsed, 2); | 428 | memcpy (&nlen, prop+bytes_parsed, 2); |
| 432 | bytes_parsed += 2; | 429 | bytes_parsed += 2; |
| 433 | if (my_bo != that_bo) nlen = SWAP16 (nlen); | 430 | if (my_bo != that_bo) nlen = swap16 (nlen); |
| 434 | if (bytes_parsed+nlen > bytes) return BadLength; | 431 | if (bytes_parsed+nlen > bytes) return BadLength; |
| 435 | to_cpy = nlen > 127 ? 127 : nlen; | 432 | to_cpy = nlen > 127 ? 127 : nlen; |
| 436 | memcpy (name, prop+bytes_parsed, to_cpy); | 433 | memcpy (name, prop+bytes_parsed, to_cpy); |
| @@ -457,7 +454,7 @@ parse_settings (unsigned char *prop, | |||
| 457 | if (want_this) | 454 | if (want_this) |
| 458 | { | 455 | { |
| 459 | memcpy (&ival, prop+bytes_parsed, 4); | 456 | memcpy (&ival, prop+bytes_parsed, 4); |
| 460 | if (my_bo != that_bo) ival = SWAP32 (ival); | 457 | if (my_bo != that_bo) ival = swap32 (ival); |
| 461 | } | 458 | } |
| 462 | bytes_parsed += 4; | 459 | bytes_parsed += 4; |
| 463 | break; | 460 | break; |
| @@ -466,7 +463,7 @@ parse_settings (unsigned char *prop, | |||
| 466 | if (bytes_parsed+4 > bytes) return BadLength; | 463 | if (bytes_parsed+4 > bytes) return BadLength; |
| 467 | memcpy (&vlen, prop+bytes_parsed, 4); | 464 | memcpy (&vlen, prop+bytes_parsed, 4); |
| 468 | bytes_parsed += 4; | 465 | bytes_parsed += 4; |
| 469 | if (my_bo != that_bo) vlen = SWAP32 (vlen); | 466 | if (my_bo != that_bo) vlen = swap32 (vlen); |
| 470 | if (want_this) | 467 | if (want_this) |
| 471 | { | 468 | { |
| 472 | to_cpy = vlen > 127 ? 127 : vlen; | 469 | to_cpy = vlen > 127 ? 127 : vlen; |