split pp_predec() from pp_preinc() and improve
authorDavid Mitchell <davem@iabyn.com>
Sun, 25 Oct 2015 08:41:50 +0000 (08:41 +0000)
committerDavid Mitchell <davem@iabyn.com>
Tue, 10 Nov 2015 13:52:34 +0000 (13:52 +0000)
pp_preinc() handles both ++$x and --$x (and the integer variants
pp_i_preinc/dec). Split it into two separate functions, as handling
both inc and dec in the same function requires 3 extra conditionals.

At the same time make the code more efficient.

As currently written it:
1) checked for "bad" SVs (such as read-only) and croaked;
2) checked for a IOK-only SV and directly incremented the IVX slot;
3) else called out to sv_inc() to handle the more complex cases.

This commit combines the checks in (1) and (2) into one single big
check of flags, and anything "bad" simply skips the IOK-only code
and calls sv_dec(), which can do its own checking of read-only etc
and croak if necessary. Porting/bench.pl shows the following raw numbers
for ++$x ($x lexical and holding an integer):

         before    after
       -------- --------
    Ir     77.0     56.0
    Dr     30.0     24.0
    Dw     10.0     10.0
  COND     12.0      9.0
   IND      2.0      2.0

COND_m     -0.1      0.0
 IND_m      2.0      2.0

Even having split the function into two, the combined size of the two new
functions is smaller than the single previous function.

opcode.h
pp_hot.c
pp_proto.h
regen/opcode.pl
t/perf/benchmarks

index 2e03448..01ed42d 100644 (file)
--- a/opcode.h
+++ b/opcode.h
@@ -22,8 +22,7 @@
 #define Perl_pp_chomp Perl_pp_chop
 #define Perl_pp_schomp Perl_pp_schop
 #define Perl_pp_i_preinc Perl_pp_preinc
-#define Perl_pp_predec Perl_pp_preinc
-#define Perl_pp_i_predec Perl_pp_preinc
+#define Perl_pp_i_predec Perl_pp_predec
 #define Perl_pp_i_postinc Perl_pp_postinc
 #define Perl_pp_postdec Perl_pp_postinc
 #define Perl_pp_i_postdec Perl_pp_postinc
@@ -1013,8 +1012,8 @@ EXT Perl_ppaddr_t PL_ppaddr[] /* or perlvars.h */
        Perl_pp_pos,
        Perl_pp_preinc,
        Perl_pp_i_preinc,       /* implemented by Perl_pp_preinc */
-       Perl_pp_predec, /* implemented by Perl_pp_preinc */
-       Perl_pp_i_predec,       /* implemented by Perl_pp_preinc */
+       Perl_pp_predec,
+       Perl_pp_i_predec,       /* implemented by Perl_pp_predec */
        Perl_pp_postinc,
        Perl_pp_i_postinc,      /* implemented by Perl_pp_postinc */
        Perl_pp_postdec,        /* implemented by Perl_pp_postinc */
index bc12290..ff9e594 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -465,25 +465,44 @@ PP(pp_eq)
 }
 
 
-/* also used for: pp_i_predec() pp_i_preinc() pp_predec() */
+/* also used for: pp_i_preinc() */
 
 PP(pp_preinc)
 {
-    dSP;
-    const bool inc =
-       PL_op->op_type == OP_PREINC || PL_op->op_type == OP_I_PREINC;
-    if (UNLIKELY(SvTYPE(TOPs) >= SVt_PVAV || (isGV_with_GP(TOPs) && !SvFAKE(TOPs))))
-       Perl_croak_no_modify();
-    if (LIKELY(!SvREADONLY(TOPs) && !SvGMAGICAL(TOPs) && SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs))
-        && SvIVX(TOPs) != (inc ? IV_MAX : IV_MIN))
+    SV *sv = *PL_stack_sp;
+
+    if (LIKELY(((sv->sv_flags &
+                        (SVf_THINKFIRST|SVs_GMG|SVf_IVisUV|
+                         SVf_IOK|SVf_NOK|SVf_POK|SVp_NOK|SVp_POK|SVf_ROK))
+                == SVf_IOK))
+        && SvIVX(sv) != IV_MAX)
+    {
+       SvIV_set(sv, SvIVX(sv) + 1);
+    }
+    else /* Do all the PERL_PRESERVE_IVUV and hard cases in sv_inc */
+       sv_inc(sv);
+    SvSETMAGIC(sv);
+    return NORMAL;
+}
+
+
+/* also used for: pp_i_predec() */
+
+PP(pp_predec)
+{
+    SV *sv = *PL_stack_sp;
+
+    if (LIKELY(((sv->sv_flags &
+                        (SVf_THINKFIRST|SVs_GMG|SVf_IVisUV|
+                         SVf_IOK|SVf_NOK|SVf_POK|SVp_NOK|SVp_POK|SVf_ROK))
+                == SVf_IOK))
+        && SvIVX(sv) != IV_MIN)
     {
-       SvIV_set(TOPs, SvIVX(TOPs) + (inc ? 1 : -1));
-       SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
+       SvIV_set(sv, SvIVX(sv) - 1);
     }
-    else /* Do all the PERL_PRESERVE_IVUV conditionals in sv_inc */
-       if (inc) sv_inc(TOPs);
-       else sv_dec(TOPs);
-    SvSETMAGIC(TOPs);
+    else /* Do all the PERL_PRESERVE_IVUV and hard cases  in sv_dec */
+       sv_dec(sv);
+    SvSETMAGIC(sv);
     return NORMAL;
 }
 
index 96934ff..440e789 100644 (file)
@@ -186,6 +186,7 @@ PERL_CALLCONV OP *Perl_pp_pipe_op(pTHX);
 PERL_CALLCONV OP *Perl_pp_pos(pTHX);
 PERL_CALLCONV OP *Perl_pp_postinc(pTHX);
 PERL_CALLCONV OP *Perl_pp_pow(pTHX);
+PERL_CALLCONV OP *Perl_pp_predec(pTHX);
 PERL_CALLCONV OP *Perl_pp_preinc(pTHX);
 PERL_CALLCONV OP *Perl_pp_print(pTHX);
 PERL_CALLCONV OP *Perl_pp_prototype(pTHX);
index 50029bd..3c5c8cf 100755 (executable)
@@ -130,7 +130,8 @@ my @raw_alias = (
                 Perl_pp_chop => [qw(chop chomp)],
                 Perl_pp_schop => [qw(schop schomp)],
                 Perl_pp_bind => {connect => '#ifdef HAS_SOCKET'},
-                Perl_pp_preinc => ['i_preinc', 'predec', 'i_predec'],
+                Perl_pp_preinc => ['i_preinc'],
+                Perl_pp_predec => ['i_predec'],
                 Perl_pp_postinc => ['i_postinc', 'postdec', 'i_postdec'],
                 Perl_pp_ehostent => [qw(enetent eprotoent eservent
                                         spwent epwent sgrent egrent)],
index 223c81f..ce8f19e 100644 (file)
         code    => '$z = $x * $y',
     },
 
+    'expr::arith::preinc' => {
+        desc    => '++$x',
+        setup   => 'my $x = 1;',
+        code    => '++$x',
+    },
+    'expr::arith::predec' => {
+        desc    => '--$x',
+        setup   => 'my $x = 1;',
+        code    => '--$x',
+    },
+    'expr::arith::postinc' => {
+        desc    => '$x++',
+        setup   => 'my $x = 1; my $y',
+        code    => '$y = $x++', # scalar context so not optimised to ++$x
+    },
+    'expr::arith::postdec' => {
+        desc    => '$x--',
+        setup   => 'my $x = 1; my $y',
+        code    => '$y = $x--', # scalar context so not optimised to --$x
+
+    },
+
 ];