refactor pp_stringify and pp_and
authorDaniel Dragan <bulk88@hotmail.com>
Tue, 20 Nov 2012 22:36:54 +0000 (17:36 -0500)
committerFather Chrysostomos <sprout@cpan.org>
Wed, 21 Nov 2012 14:04:11 +0000 (06:04 -0800)
pp_stringify:

First, move all the SP/stack operations to before the first call in
pp_stringify (sv_copypv), this allows SP to never be saved across any calls.
SETTARG calls set magic, so that still has to be done. SETs does not ++/--
SP, so no need to do a PUTBACK. PL_op is read twice, once for TARG, once
for NORMAL. No point in caching it through the sv_copypv call since its not
worth saving a non-vol to C stack (x86) just to avoid 2 mem acesses. This
opcode now only has 2 vars saved across sv_copypv, my_perl and TARG.

pp_stringify dropped from 0x3F to 0x3C for me after these changes, 32 bit
x86 VC 2003.

pp_and:

Do the PERL_ASYNC_CHECK before anything else, calcing SP before
PERL_ASYNC_CHECK would mean saving it across the potential call. SvTRUE
macro checks its param for NULL. This SV * came off the Perl stack, it will
not be null since pp_and is not a core sub (see S_maybe_add_coresub) and
will not be called from pp_coreargs (pp_coreargs places (SV *)NULLs on
Perl stack). So create a SvTRUE_NN macro that does not check for NULL, this
saves a branch. Since the Perl stack is only touched twice, don't create
a local SP. See comment in code. This saves another variable to not be
saved across the sv_2bool_flags and removed PUTBACK instructions. PL_op is
only read once or twice (compiler choice) right before the 2 returns.
There is only 1 variable saved across any calls in pp_and now, and that is
my_perl. dSP also was not use to prevent an accidental use of a ++/-- SP
macro in pp_and in the future since there is no PUTBACK now. I guess for a
SPARC with register windowing and no direct memory instructions, accessing
PL_stack_sp twice will take more instructions 2 reads and a write to
PL_stack_sp vs 1 read and 1 write to PL_stack_sp with a dSP design. On
SPARC, with a register window, cross call regs have no cost per reg cost
aslong as you dont exceed their max number.

For me, pp_and went from 0x112 to 0xFF after this commit. Prior to dSP
removal, it was down to 0x109. SvTRUE_NN was named after SvREFCNT_inc_NN.
There remains an inefficiency in pp_and on non-GCC compilers due to
SvPVXtrue using PL_Xpv which will be dealt with in another commit.

pp_hot.c
sv.h

index d535434..977e22f 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -85,9 +85,12 @@ PP(pp_pushmark)
 PP(pp_stringify)
 {
     dVAR; dSP; dTARGET;
-    sv_copypv(TARG,TOPs);
-    SETTARG;
-    RETURN;
+    SV * const sv = TOPs;
+    SETs(TARG);
+    sv_copypv(TARG, sv);
+    SvSETMAGIC(TARG);
+    /* no PUTBACK, SETs doesn't inc/dec SP */
+    return NORMAL;
 }
 
 PP(pp_gv)
@@ -99,14 +102,22 @@ PP(pp_gv)
 
 PP(pp_and)
 {
-    dVAR; dSP;
+    dVAR;
     PERL_ASYNC_CHECK();
-    if (!SvTRUE(TOPs))
-       RETURN;
-    else {
-        if (PL_op->op_type == OP_AND)
-           --SP;
-       RETURNOP(cLOGOP->op_other);
+    {
+       /* SP is not used to remove a variable that is saved across the
+         sv_2bool_flags call in SvTRUE_NN, if a RISC/CISC or low/high machine
+         register or load/store vs direct mem ops macro is introduced, this
+         should be a define block between direct PL_stack_sp and dSP operations,
+         presently, using PL_stack_sp is bias towards CISC cpus */
+       SV * const sv = *PL_stack_sp;
+       if (!SvTRUE_NN(sv))
+           return NORMAL;
+       else {
+           if (PL_op->op_type == OP_AND)
+               --PL_stack_sp;
+           return cLOGOP->op_other;
+       }
     }
 }
 
diff --git a/sv.h b/sv.h
index 902cae7..35b360f 100644 (file)
--- a/sv.h
+++ b/sv.h
@@ -1708,6 +1708,7 @@ Like sv_utf8_upgrade, but doesn't do magic on C<sv>.
 
 #define SvTRUE(sv)        ((sv) && (SvGMAGICAL(sv) ? sv_2bool(sv) : SvTRUE_common(sv, sv_2bool_nomg(sv))))
 #define SvTRUE_nomg(sv)   ((sv) && (                                SvTRUE_common(sv, sv_2bool_nomg(sv))))
+#define SvTRUE_NN(sv)              (SvGMAGICAL(sv) ? sv_2bool(sv) : SvTRUE_common(sv, sv_2bool_nomg(sv)))
 #define SvTRUE_common(sv,fallback) (                   \
       !SvOK(sv)                                                \
        ? 0                                             \