In perl.git, the branch blead has been updated <https://perl5.git.perl.org/perl.git/commitdiff/b877c1ff7374e89bad1d494c2a847af552d40782?hp=ef65a74af186beb93566cf827c5f543f4aa14645>
- Log ----------------------------------------------------------------- commit b877c1ff7374e89bad1d494c2a847af552d40782 Author: Karl Williamson <[email protected]> Date: Thu Mar 21 10:14:37 2019 -0600 handy.h: Change some macros to use new inRANGE It turns out that on ASCII platforms, several of the character classes are expressible as a single range, and using the new inRANGE macro saves some instructions each time versus the array lookup still done for these on EBCDIC platforms. Here is a sample benchmark Key: Ir Instruction read Dr Data read Dw Data write COND conditional branches IND indirect branches The numbers represent raw counts per loop iteration. isDIGIT_A('5') blead hack Ratio % ----- ----- ------- Ir 358.0 355.0 100.8 Dr 123.0 121.0 101.7 Dw 57.0 57.0 100.0 COND 51.0 50.0 102.0 IND 7.0 7.0 100.0 The differences are small, but these macros are executed ubiquitously commit 305fe86ebe53ebaec4b94533f37a83774647e346 Author: Karl Williamson <[email protected]> Date: Wed Mar 20 15:31:03 2019 -0600 Generalize macro and move to handy.h The macro verified that its input was in the range '1' to '9' by using a subtraction and a single conditional. This commit generalizes this non-obvious method of avoiding a conditional, and moves it to handy.h so it can be used in other places. ----------------------------------------------------------------------- Summary of changes: handy.h | 26 ++++++++++++++++++++------ sv.c | 18 ++++++------------ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/handy.h b/handy.h index 57ad62dc61..3ce0b1bca7 100644 --- a/handy.h +++ b/handy.h @@ -1094,6 +1094,12 @@ patched there. The file as of this writing is cpan/Devel-PPPort/parts/inc/misc #define FITS_IN_8_BITS(c) (1) #endif +/* Returns true if c is in the range l..u + * Written with the cast so it only needs one conditional test + */ +#define inRANGE(c, l, u) (__ASSERT_((u) >= (l)) \ + ((WIDEST_UTYPE) (((c) - (l)) | 0) <= ((WIDEST_UTYPE) ((u) - (l))))) + #ifdef EBCDIC # ifndef _ALL_SOURCE /* The native libc isascii() et.al. functions return the wrong results @@ -1248,17 +1254,25 @@ END_EXTERN_C && ((PL_charclass[(U8) (c)] & _CC_mask_A(classnum)) \ == _CC_mask_A(classnum))) -# define isALPHA_A(c) _generic_isCC_A(c, _CC_ALPHA) +# ifdef EBCDIC +# define isALPHA_A(c) _generic_isCC_A(c, _CC_ALPHA) +# define isGRAPH_A(c) _generic_isCC_A(c, _CC_GRAPH) +# define isLOWER_A(c) _generic_isCC_A(c, _CC_LOWER) +# define isPRINT_A(c) _generic_isCC_A(c, _CC_PRINT) +# define isUPPER_A(c) _generic_isCC_A(c, _CC_UPPER) +# else +# define isALPHA_A(c) inRANGE((~('A' ^ 'a') & (c)), 'A', 'Z') +# define isGRAPH_A(c) inRANGE((c), ' ' + 1, 0x7e) +# define isLOWER_A(c) inRANGE(c, 'a', 'z') +# define isPRINT_A(c) inRANGE(c, ' ', 0x7e) +# define isUPPER_A(c) inRANGE(c, 'A', 'Z') +# endif # define isALPHANUMERIC_A(c) _generic_isCC_A(c, _CC_ALPHANUMERIC) # define isBLANK_A(c) _generic_isCC_A(c, _CC_BLANK) # define isCNTRL_A(c) _generic_isCC_A(c, _CC_CNTRL) -# define isDIGIT_A(c) _generic_isCC(c, _CC_DIGIT) /* No non-ASCII digits */ -# define isGRAPH_A(c) _generic_isCC_A(c, _CC_GRAPH) -# define isLOWER_A(c) _generic_isCC_A(c, _CC_LOWER) -# define isPRINT_A(c) _generic_isCC_A(c, _CC_PRINT) +# define isDIGIT_A(c) inRANGE(c, '0', '9') # define isPUNCT_A(c) _generic_isCC_A(c, _CC_PUNCT) # define isSPACE_A(c) _generic_isCC_A(c, _CC_SPACE) -# define isUPPER_A(c) _generic_isCC_A(c, _CC_UPPER) # define isWORDCHAR_A(c) _generic_isCC_A(c, _CC_WORDCHAR) # define isXDIGIT_A(c) _generic_isCC(c, _CC_XDIGIT) /* No non-ASCII xdigits */ diff --git a/sv.c b/sv.c index e9a46827d3..b6d9123971 100644 --- a/sv.c +++ b/sv.c @@ -11071,12 +11071,6 @@ S_sprintf_arg_num_val(pTHX_ va_list *const args, int i, SV *sv, bool *neg) return (STRLEN)iv; } - -/* Returns true if c is in the range '1'..'9' - * Written with the cast so it only needs one conditional test - */ -#define IS_1_TO_9(c) ((U8)(c - '1') <= 8) - /* Read in and return a number. Updates *pattern to point to the char * following the number. Expects the first char to 1..9. * Croaks if the number exceeds 1/4 of the maximum value of STRLEN. @@ -11093,7 +11087,7 @@ S_expect_number(pTHX_ const char **const pattern) PERL_ARGS_ASSERT_EXPECT_NUMBER; - assert(IS_1_TO_9(**pattern)); + assert(inRANGE(**pattern, '1', '9')); var = *(*pattern)++ - '0'; while (isDIGIT(**pattern)) { @@ -12042,7 +12036,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p [%bcdefginopsuxDFOUX] format (mandatory) */ - if (IS_1_TO_9(*q)) { + if (inRANGE(*q, '1', '9')) { width = expect_number(&q); if (*q == '$') { if (args) @@ -12110,7 +12104,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p if (*q == '*') { STRLEN ix; /* explicit width/vector separator index */ q++; - if (IS_1_TO_9(*q)) { + if (inRANGE(*q, '1', '9')) { ix = expect_number(&q); if (*q++ == '$') { if (args) @@ -12182,7 +12176,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p fill = TRUE; q++; } - if (IS_1_TO_9(*q)) + if (inRANGE(*q, '1', '9')) width = expect_number(&q); } @@ -12195,7 +12189,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p if (*q == '*') { STRLEN ix; /* explicit precision index */ q++; - if (IS_1_TO_9(*q)) { + if (inRANGE(*q, '1', '9')) { ix = expect_number(&q); if (*q++ == '$') { if (args) @@ -12234,7 +12228,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p */ while (*q == '0') q++; - precis = IS_1_TO_9(*q) ? expect_number(&q) : 0; + precis = inRANGE(*q, '1', '9') ? expect_number(&q) : 0; has_precis = TRUE; } } -- Perl5 Master Repository
