refactor pp_rand
authorDaniel Dragan <bulk88@hotmail.com>
Sat, 17 Nov 2012 07:20:50 +0000 (02:20 -0500)
committerFather Chrysostomos <sprout@cpan.org>
Sat, 17 Nov 2012 21:49:08 +0000 (13:49 -0800)
Reduce liveness of various variables. srand relies on nothing but a THX
so do that first and don't calculate a local SP yet. Put the EXTEND near SP
calculation. This might refresh SP. MAXARG access PL_op. The POPs balances
the stack. var sv is kept in a volatile, it is out of scope after the SvNV.
Through the SvNV, only 2 autos/regs are carried my_perl and SP.
dTARGET again uses PL_op but it and PUSHs and PUTBACK make no calls. SP is
out of scope after the PUTBACK. In macro Drand01 is the next call. XPUSHn
uses SvSETMAGIC. This is replaced with sv_setnv_mg since rand is not hot.
Now TARG is out of scope. Only my_perl remains in scope. NORMAL uses
PL_op for the 3rd and final time. All x86 32bit C stack usage was for
saving nonvol regs and 2 auto NVs (asm limitations prevent from keeping
it in a normal reg I guess)(VC2003). Caching PL_op->op_next at dTARGET to
avoid a 3rd PL_op dereference was tried with

SV * targ; (op_next = NORMAL), (GETTARGET), (PUSHs(TARG)), (PUTBACK);

to allow reordering, but it generated a stack auto on Visual C even
though 1 non vol reg (edi) was available. Another untried idea would be to
declare a OP * and set it to PL_op, then do the op_next and op_targ derefs,
but with the above mess, PL_op was derefed once by compiler optimization
but still the stack var was used. Also maintainability contributed to
scrapping  the idea. The 1.0 assigns are reordered by comp in a way
that all of them happen after the SvNV but before the next call, which
is rand(), so they are fine order of execution wise. The comment about
SP or TARG means either dTARGET is done before the SvNV and SP is out of
scope before SvNV but SV * targ has to be saved across the SvNV, or SP is
saved across the SvNV. A choice was made save SP since the C code would
be more complicated, probably with gotos and initialing sv to NULL if
dTARGET/PUTBACK had to happen after conditional MAXARG/TOPs
unconditionally, but SvNV is conditonally called. The improvements in
this commit are not specific to x86-32 but all platforms and cpus.

The function dropped from 0xFF to 0xEB for me.

pp.c

index 52f5d39..02ad594 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -2695,24 +2695,37 @@ extern double drand48 (void);
 
 PP(pp_rand)
 {
-    dVAR; dSP; dTARGET;
-    NV value;
-    if (MAXARG < 1)
-       value = 1.0;
-    else if (!TOPs) {
-       value = 1.0; (void)POPs;
-    }
-    else
-       value = POPn;
-    if (value == 0.0)
-       value = 1.0;
+    dVAR;
     if (!PL_srand_called) {
        (void)seedDrand01((Rand_seed_t)seed());
        PL_srand_called = TRUE;
     }
-    value *= Drand01();
-    XPUSHn(value);
-    RETURN;
+    {
+       dSP;
+       NV value;
+       EXTEND(SP, 1);
+    
+       if (MAXARG < 1)
+           value = 1.0;
+       else {
+           SV * const sv = POPs;
+           if(!sv)
+               value = 1.0;
+           else
+               value = SvNV(sv);
+       }
+    /* 1 of 2 things can be carried through SvNV, SP or TARG, SP was carried */
+       if (value == 0.0)
+           value = 1.0;
+       {
+           dTARGET;
+           PUSHs(TARG);
+           PUTBACK;
+           value *= Drand01();
+           sv_setnv_mg(TARG, value);
+       }
+    }
+    return NORMAL;
 }
 
 PP(pp_srand)