summaryrefslogtreecommitdiff
path: root/av.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2016-08-17 12:06:27 +0100
committerDavid Mitchell <davem@iabyn.com>2016-08-17 13:39:24 +0100
commitf4d8be8b395cdacf05f8c461fb7e9ce0366ff56f (patch)
tree87ffdc5f105230dcea6446fcb2ea3da5852c0ee7 /av.c
parent11b62bc4c2460b23807b5c84c6e8b463068cf886 (diff)
downloadperl-f4d8be8b395cdacf05f8c461fb7e9ce0366ff56f.tar.gz
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.
Diffstat (limited to 'av.c')
-rw-r--r--av.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/av.c b/av.c
index 549ca6c86e..8f8cda5c57 100644
--- a/av.c
+++ b/av.c
@@ -244,6 +244,9 @@ 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);
@@ -268,15 +271,19 @@ Perl_av_fetch(pTHX_ AV *av, SSize_t key, I32 lval)
}
}
- if (key < 0) {
- key += AvFILLp(av) + 1;
- if (UNLIKELY(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;
- assert(key <= AvFILLp(av));
- if (!AvARRAY(av)[key])
- goto emptyness;
+ goto emptyness;
}
- else if (key > AvFILLp(av) || !AvARRAY(av)[key]) {
+
+ if (!AvARRAY(av)[key]) {
emptyness:
return lval ? av_store(av,key,newSV(0)) : NULL;
}