summaryrefslogtreecommitdiff
path: root/pp.c
diff options
context:
space:
mode:
authorDaniel Dragan <bulk88@hotmail.com>2012-11-17 02:20:50 -0500
committerFather Chrysostomos <sprout@cpan.org>2012-11-17 13:49:08 -0800
commitfdf4dddd9dbb73e29cd736f1be8a86925999c9b8 (patch)
treeca914996795c0ebd51235673d06af8f7718d66a2 /pp.c
parentdd82de44921d6cabc07c0ea8d733e7aed7285a63 (diff)
downloadperl-fdf4dddd9dbb73e29cd736f1be8a86925999c9b8.tar.gz
refactor pp_rand
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.
Diffstat (limited to 'pp.c')
-rw-r--r--pp.c41
1 files changed, 27 insertions, 14 deletions
diff --git a/pp.c b/pp.c
index 52f5d39d87..02ad594cbd 100644
--- 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)