* Re: master b467bb5 4/4: Minimize ‘equal’ calls in (delete x vector) [not found] ` <20200815181959.E7DC3209AC@vcs0.savannah.gnu.org> @ 2020-08-15 19:00 ` Pip Cet 2020-08-15 19:22 ` Pip Cet 0 siblings, 1 reply; 5+ messages in thread From: Pip Cet @ 2020-08-15 19:00 UTC (permalink / raw) To: emacs-devel, Paul Eggert On Sat, Aug 15, 2020 at 6:20 PM Paul Eggert <eggert@cs.ucla.edu> wrote: > > branch: master > commit b467bb531e1ab0eed57e1889004d2115e80e4292 > Author: Paul Eggert <eggert@cs.ucla.edu> > Commit: Paul Eggert <eggert@cs.ucla.edu> > > Minimize ‘equal’ calls in (delete x vector) > > * src/fns.c (Fdelete): When deleting from a vector, call Fequal > only once per vector element. This is faster when Fequal is slow, > and avoids the need to preinitialize the vector result. Finish > when the result is exhausted, not when the input is exhausted; > the two are equivalent but the former may be faster. > * test/src/fns-tests.el (test-vector-delete): New test. > --- > src/fns.c | 38 +++++++++++++++++++++++++++++--------- > test/src/fns-tests.el | 5 +++++ > 2 files changed, 34 insertions(+), 9 deletions(-) > > diff --git a/src/fns.c b/src/fns.c > index c89bd81..069edbe 100644 > --- a/src/fns.c > +++ b/src/fns.c > @@ -1747,22 +1747,42 @@ changing the value of a sequence `foo'. */) > { > if (VECTORP (seq)) > { > - ptrdiff_t i, n; > + ptrdiff_t n = 0; > + ptrdiff_t size = ASIZE (seq); > + ptrdiff_t neqbits_words = ((size + BITS_PER_BITS_WORD - 1) > + / BITS_PER_BITS_WORD); > + USE_SAFE_ALLOCA; > + bits_word *neqbits = SAFE_ALLOCA (neqbits_words * sizeof *neqbits); > + bits_word neqword = 0; > > - for (i = n = 0; i < ASIZE (seq); ++i) > - if (NILP (Fequal (AREF (seq, i), elt))) > - ++n; This code looks wrong to me: > + for (ptrdiff_t i = 0; i < size; i++) > + { > + bool neq = NILP (Fequal (AREF (seq, i), elt)); > + n += neq; > + neqbits[i / BITS_PER_BITS_WORD] = neqword = (neqword << 1) + neq; > + } That left-shifts the first sequence element's bit left by up to 63 times. But ... > + for (ptrdiff_t i = 0; ; i++) > + if (neqbits[i / BITS_PER_BITS_WORD] > + & ((bits_word) 1 << (i % BITS_PER_BITS_WORD))) this checks the non-left-shifted LSB for the first sequence element. Indeed, we have (delete t [nil t]) => [t] which is nonsensical. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: master b467bb5 4/4: Minimize ‘equal’ calls in (delete x vector) 2020-08-15 19:00 ` master b467bb5 4/4: Minimize ‘equal’ calls in (delete x vector) Pip Cet @ 2020-08-15 19:22 ` Pip Cet 2020-08-15 19:42 ` Paul Eggert 0 siblings, 1 reply; 5+ messages in thread From: Pip Cet @ 2020-08-15 19:22 UTC (permalink / raw) To: emacs-devel, Paul Eggert [-- Attachment #1: Type: text/plain, Size: 265 bytes --] On Sat, Aug 15, 2020 at 7:00 PM Pip Cet <pipcet@gmail.com> wrote: > Indeed, we have > > (delete t [nil t]) => [t] > > which is nonsensical. In fact, I'd prefer the attached: this is probably not worth worrying too much about, so go with something straightforward? [-- Attachment #2: 0001-Fix-delete-t-nil-t.patch --] [-- Type: text/x-patch, Size: 1542 bytes --] From 7e25be845efcb0ff6043b6100aaf81f6b8c9cafa Mon Sep 17 00:00:00 2001 From: Pip Cet <pipcet@gmail.com> Date: Sat, 15 Aug 2020 19:20:27 +0000 Subject: [PATCH] Fix (delete t [nil t]). --- src/fns.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/src/fns.c b/src/fns.c index 069edbe90e..33c66aeef6 100644 --- a/src/fns.c +++ b/src/fns.c @@ -1749,35 +1749,19 @@ DEFUN ("delete", Fdelete, Sdelete, 2, 2, 0, { ptrdiff_t n = 0; ptrdiff_t size = ASIZE (seq); - ptrdiff_t neqbits_words = ((size + BITS_PER_BITS_WORD - 1) - / BITS_PER_BITS_WORD); USE_SAFE_ALLOCA; - bits_word *neqbits = SAFE_ALLOCA (neqbits_words * sizeof *neqbits); - bits_word neqword = 0; + ptrdiff_t *posns = SAFE_ALLOCA (size * sizeof posns[0]); for (ptrdiff_t i = 0; i < size; i++) - { - bool neq = NILP (Fequal (AREF (seq, i), elt)); - n += neq; - neqbits[i / BITS_PER_BITS_WORD] = neqword = (neqword << 1) + neq; - } + if (NILP (Fequal (AREF (seq, i), elt))) + posns[n++] = i; if (n != size) { struct Lisp_Vector *p = allocate_vector (n); - if (n != 0) - { - ptrdiff_t j = 0; - for (ptrdiff_t i = 0; ; i++) - if (neqbits[i / BITS_PER_BITS_WORD] - & ((bits_word) 1 << (i % BITS_PER_BITS_WORD))) - { - p->contents[j++] = AREF (seq, i); - if (j == n) - break; - } - } + for (ptrdiff_t j = 0; j < n; j++) + p->contents[j] = AREF (seq, posns[j]); XSETVECTOR (seq, p); } -- 2.28.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: master b467bb5 4/4: Minimize ‘equal’ calls in (delete x vector) 2020-08-15 19:22 ` Pip Cet @ 2020-08-15 19:42 ` Paul Eggert 2020-08-15 20:21 ` Pip Cet 0 siblings, 1 reply; 5+ messages in thread From: Paul Eggert @ 2020-08-15 19:42 UTC (permalink / raw) To: Pip Cet; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 493 bytes --] On 8/15/20 12:22 PM, Pip Cet wrote: > I'd prefer the attached: this is probably not worth worrying > too much about, so go with something straightforward? Thanks for the quick review and patch. I came up with something a bit simpler and installed the attached. It does bug me a bit that GCC generates bad code for 'NILP (Fequal (...))' here. I've been meaning to add a bool function equal (...) that would simplify the C source a bit and presumably let GCC do better, but that can wait. [-- Attachment #2: 0001-Fix-recently-introduced-Fdelete-bug.patch --] [-- Type: text/x-patch, Size: 2472 bytes --] From 748afc183c2c44b7b2a582d3078cf3d8b4d5270a Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Sat, 15 Aug 2020 12:32:56 -0700 Subject: [PATCH] Fix recently-introduced Fdelete bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem reported by Pip Cet in: https://lists.gnu.org/r/emacs-devel/2020-08/msg00444.html * src/fns.c (Fdelete): Fix correctness bug via a simpler (though more memory-intensive) approach. It’s probably not worth optimizing the memory usage yere. * test/src/fns-tests.el (test-vector-delete): Add test for the bug. --- src/fns.c | 29 ++++------------------------- test/src/fns-tests.el | 1 + 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/src/fns.c b/src/fns.c index 069edbe90e..a3b8d6ef57 100644 --- a/src/fns.c +++ b/src/fns.c @@ -1749,38 +1749,17 @@ DEFUN ("delete", Fdelete, Sdelete, 2, 2, 0, { ptrdiff_t n = 0; ptrdiff_t size = ASIZE (seq); - ptrdiff_t neqbits_words = ((size + BITS_PER_BITS_WORD - 1) - / BITS_PER_BITS_WORD); USE_SAFE_ALLOCA; - bits_word *neqbits = SAFE_ALLOCA (neqbits_words * sizeof *neqbits); - bits_word neqword = 0; + Lisp_Object *kept = SAFE_ALLOCA (size * sizeof *kept); for (ptrdiff_t i = 0; i < size; i++) { - bool neq = NILP (Fequal (AREF (seq, i), elt)); - n += neq; - neqbits[i / BITS_PER_BITS_WORD] = neqword = (neqword << 1) + neq; + kept[n] = AREF (seq, i); + n += NILP (Fequal (AREF (seq, i), elt)); } if (n != size) - { - struct Lisp_Vector *p = allocate_vector (n); - - if (n != 0) - { - ptrdiff_t j = 0; - for (ptrdiff_t i = 0; ; i++) - if (neqbits[i / BITS_PER_BITS_WORD] - & ((bits_word) 1 << (i % BITS_PER_BITS_WORD))) - { - p->contents[j++] = AREF (seq, i); - if (j == n) - break; - } - } - - XSETVECTOR (seq, p); - } + seq = Fvector (n, kept); SAFE_FREE (); } diff --git a/test/src/fns-tests.el b/test/src/fns-tests.el index 141de1d226..400e912648 100644 --- a/test/src/fns-tests.el +++ b/test/src/fns-tests.el @@ -898,5 +898,6 @@ test-secure-hash (ert-deftest test-vector-delete () (let ((v1 (make-vector 1000 1))) + (should (equal (delete t [nil t]) [nil])) (should (equal (delete 1 v1) (vector))) (should (equal (delete 2 v1) v1)))) -- 2.17.1 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: master b467bb5 4/4: Minimize ‘equal’ calls in (delete x vector) 2020-08-15 19:42 ` Paul Eggert @ 2020-08-15 20:21 ` Pip Cet 2020-08-16 0:49 ` Paul Eggert 0 siblings, 1 reply; 5+ messages in thread From: Pip Cet @ 2020-08-15 20:21 UTC (permalink / raw) To: Paul Eggert; +Cc: emacs-devel On Sat, Aug 15, 2020 at 7:42 PM Paul Eggert <eggert@cs.ucla.edu> wrote: > On 8/15/20 12:22 PM, Pip Cet wrote: > > > I'd prefer the attached: this is probably not worth worrying > > too much about, so go with something straightforward? > > Thanks for the quick review and patch. I came up with something a bit simpler > and installed the attached. Looks correct, but establishes a rather questionable precedent of putting Lisp_Objects in SAFE_ALLOCA'd space. That's okay in this specific case, for a number of reasons, but it's bound to be copied by someone in circumstances where it's not :-) > It does bug me a bit that GCC generates bad code for 'NILP (Fequal (...))' here. > I've been meaning to add a bool function equal (...) that would simplify the C > source a bit and presumably let GCC do better, but that can wait. What's GCC doing, for you? I see that it doesn't eliminate the potentially dead store to kept[n] here, but other than that the code looks okay to me. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: master b467bb5 4/4: Minimize ‘equal’ calls in (delete x vector) 2020-08-15 20:21 ` Pip Cet @ 2020-08-16 0:49 ` Paul Eggert 0 siblings, 0 replies; 5+ messages in thread From: Paul Eggert @ 2020-08-16 0:49 UTC (permalink / raw) To: Pip Cet; +Cc: emacs-devel On 8/15/20 1:21 PM, Pip Cet wrote: > Looks correct, but establishes a rather questionable precedent of > putting Lisp_Objects in SAFE_ALLOCA'd space. That's okay in this > specific case, for a number of reasons, but it's bound to be copied by > someone in circumstances where it's not :-) It's not unprecedented, as there's one other instance of this, in font_sort_entities. Admittedly it's unusual; feel free to add a comment. >> It does bug me a bit that GCC generates bad code for 'NILP (Fequal (...))' here. >> I've been meaning to add a bool function equal (...) that would simplify the C >> source a bit and presumably let GCC do better, but that can wait. > > What's GCC doing, for you? It's doing some weird thing involving cmp + adc. On second thought it's probably fine, as it is branch-free. Still, I always get confused when I write "!NILP (Fequal (a, b)' and too often I get it wrong. I'd rather write 'equal (a, b)'. ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2020-08-16 0:49 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- [not found] <20200815181956.27401.76683@vcs0.savannah.gnu.org> [not found] ` <20200815181959.E7DC3209AC@vcs0.savannah.gnu.org> 2020-08-15 19:00 ` master b467bb5 4/4: Minimize ‘equal’ calls in (delete x vector) Pip Cet 2020-08-15 19:22 ` Pip Cet 2020-08-15 19:42 ` Paul Eggert 2020-08-15 20:21 ` Pip Cet 2020-08-16 0:49 ` Paul Eggert
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).