In perl.git, the branch blead has been updated <http://perl5.git.perl.org/perl.git/commitdiff/f4d8be8b395cdacf05f8c461fb7e9ce0366ff56f?hp=96e6a0bc89e2585b9ed65f699450f6c52ee6aadc>
- Log ----------------------------------------------------------------- commit f4d8be8b395cdacf05f8c461fb7e9ce0366ff56f Author: David Mitchell <[email protected]> Date: Wed Aug 17 12:06:27 2016 +0100 av_fetch(): use less branches. The code that handles negative array indexes and out-of-bounds negative indices used to require: 2 conditions for a +ve index 3 conditions for a -ve index After this commit, for the common case where the index is in bounds, it requires a single condition regardless of sign. For the less common case of out-of-bounds, it requires 2 conditions. Also, the one condition is more branch-predict friendly - it's whether the index is in bounds or not. Previously the first test was whether key < 0, and in code that does mixed signs, such as $a[0] + $a[-1], branch prediction could be tricky. It achieves this at the expense of a more complex expression for the key. M av.c commit 11b62bc4c2460b23807b5c84c6e8b463068cf886 Author: David Mitchell <[email protected]> Date: Wed Aug 17 11:18:46 2016 +0100 av_fetch(): sprinkle UNLIKELY() M av.c commit 93a3e97518c1f1e5d6916e1550a36f0d39d520e6 Author: David Mitchell <[email protected]> Date: Wed Aug 17 09:59:06 2016 +0100 av_fetch(): optimise the negative index branch. For a negative index one conditional is redundant, since after determining that key < 0 and recomputing key as (AvFILLp(av) - key), key can't be > AvFILLp(av). M av.c commit 1d7e6444bd515142acf34ef230b50f9d80ab9017 Author: David Mitchell <[email protected]> Date: Wed Aug 17 09:52:48 2016 +0100 av_fetch(): use AvFILLp rather than AvFILL The point in the code which uses AvFILL will never be reached if the array is tied, so use AvFILLp insead, which directly accesses the xav_fill field. This only affects the $a[-N] branch: the $a[+N] branch already uses AvFILLp(). M av.c ----------------------------------------------------------------------- Summary of changes: av.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/av.c b/av.c index 2f81971..8f8cda5 100644 --- a/av.c +++ b/av.c @@ -244,10 +244,13 @@ S_adjust_index(pTHX_ AV *av, const MAGIC *mg, SSize_t *keyp) SV** Perl_av_fetch(pTHX_ AV *av, SSize_t key, I32 lval) { + SSize_t neg; + SSize_t size; + PERL_ARGS_ASSERT_AV_FETCH; assert(SvTYPE(av) == SVt_PVAV); - if (SvRMAGICAL(av)) { + if (UNLIKELY(SvRMAGICAL(av))) { const MAGIC * const tied_magic = mg_find((const SV *)av, PERL_MAGIC_tied); if (tied_magic || mg_find((const SV *)av, PERL_MAGIC_regdata)) { @@ -268,18 +271,24 @@ Perl_av_fetch(pTHX_ AV *av, SSize_t key, I32 lval) } } - if (key < 0) { - key += AvFILL(av) + 1; - if (key < 0) + neg = (key < 0); + size = AvFILLp(av) + 1; + key += neg * size; /* handle negative index without using branch */ + + /* the cast from SSize_t to Size_t allows both (key < 0) and (key >= size) + * to be tested as a single condition */ + if ((Size_t)key >= (Size_t)size) { + if (UNLIKELY(neg)) return NULL; + goto emptyness; } - if (key > AvFILLp(av) || !AvARRAY(av)[key]) { + if (!AvARRAY(av)[key]) { emptyness: return lval ? av_store(av,key,newSV(0)) : NULL; } - if (AvREIFY(av) && SvIS_FREED(AvARRAY(av)[key])) { + if (UNLIKELY(AvREIFY(av) && SvIS_FREED(AvARRAY(av)[key]))) { /* eg. @_ could have freed elts */ AvARRAY(av)[key] = NULL; /* 1/2 reify */ goto emptyness; -- Perl5 Master Repository
