Skip to content

Commit 080bee0

Browse files
committed
grok_bin_oct_hex: Shortcut leading zeros
I noticed that leading zeros are quite common for octal and hex constants. This code is structured for speed, with a partially unrolled loop structured so that it is impossible to overflow the unrolled part. If we get to the end of the unrolled portion, and the accumulated value is still zero, it's because there have been only leading zeroes so far, and instead of dropping into the loop, we can re-enter the unrolled part without having to consider the possibility of overflowing. This allows the next chunk of digits to be processed without branching.
1 parent 29d187e commit 080bee0

File tree

1 file changed

+20
-1
lines changed

1 file changed

+20
-1
lines changed

numeric.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ Perl_grok_bin_oct_hex(pTHX_ const char *start,
427427

428428
/* Unroll the loop so that the first 8 digits are branchless except for the
429429
* switch. A ninth hex one overflows a 32 bit word. */
430+
redo_switch:
430431
switch (e - s) {
431432
default:
432433
if (UNLIKELY(! generic_isCC_(*s, class_bit))) break;
@@ -473,6 +474,15 @@ Perl_grok_bin_oct_hex(pTHX_ const char *start,
473474
return value;
474475
}
475476

477+
/* If we get here, and the accumulated value is still 0, it is
478+
* because there are more leading zeros than the cases of this
479+
* switch(), These are common enough with these kinds of
480+
* binary-style numbers that it is worth this extra conditional to
481+
* continue absorbing them via the switch. */
482+
if (value == 0) {
483+
goto redo_switch;
484+
}
485+
476486
break;
477487
}
478488

@@ -549,7 +559,16 @@ Perl_grok_bin_oct_hex(pTHX_ const char *start,
549559
!= PERL_SCAN_ALLOW_MEDIAL_UNDERSCORES)))
550560
{
551561
++s;
552-
goto redo;
562+
563+
/* To get here with the value so-far being 0 means we've only had
564+
* leading zeros, then an underscore. We can continue with the
565+
* branchless switch() instead of this loop */
566+
if (value == 0) {
567+
goto redo_switch;
568+
}
569+
else {
570+
goto redo;
571+
}
553572
}
554573

555574
if (*s) {

0 commit comments

Comments
 (0)