From edba15b0ccf22f00ea6d7cc58eb2c173437a09cc Mon Sep 17 00:00:00 2001 From: David Mitchell Date: Thu, 22 Oct 2015 16:43:49 +0100 Subject: [PATCH] make SETi/u/n, (X)PUSHi/u/n more efficient These macros are used by many pp functions to set TARG to an int or float value and put it on the stack. The macros use a call to sv_setiv() or similar. However, there is a good chance that the target is ether a lexical var or a PADTMP that has been assigned just an IV/NV in the past, in which case its body is likely to still be of type SVt_IV/SVt_NV. If this is the case, we can set its value much more efficiently. Update those setting macros to first check if the target has a simple body, and if so, set directly. This makes quite a significant performance difference on code that does a lot of arithmetic, at the cost of a larger binary (0.36% on my Linux x86_64 system). It also allows you (at compile time) to skip testing for taint if you know that the value can't be tainted (e.g. pp_add() when both args are non-magical and so can't have taint magic attached). The next commit will make use of this. Includes a couple of efficiency tweaks suggested by Daniel Dragan. --- pp.h | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 9 deletions(-) diff --git a/pp.h b/pp.h index 5712b8eeeb..945d1e5aa3 100644 --- a/pp.h +++ b/pp.h @@ -371,19 +371,85 @@ Does not use C. See also C>, C> and C>. } } STMT_END #endif +/* set TARG to the IV value i. If do_taint is false, + * assume that PL_tainted can never be true */ +#define TARGi(i, do_taint) \ + STMT_START { \ + IV TARGi_iv = i; \ + if (LIKELY( \ + ((SvFLAGS(TARG) & (SVTYPEMASK|SVf_THINKFIRST)) == SVt_IV) \ + & (do_taint ? !TAINT_get : 1))) \ + { \ + /* Cheap SvIOK_only(). \ + * Assert that flags which SvIOK_only() would test or \ + * clear can't be set, because we're SVt_IV */ \ + assert(!(SvFLAGS(TARG) & \ + (SVf_OOK|SVf_UTF8|(SVf_OK & ~(SVf_IOK|SVp_IOK))))); \ + SvFLAGS(TARG) |= (SVf_IOK|SVp_IOK); \ + /* SvIV_set() where sv_any points to head */ \ + TARG->sv_u.svu_iv = TARGi_iv; \ + } \ + else \ + sv_setiv_mg(targ, TARGi_iv); \ + } STMT_END + +/* set TARG to the UV value u. If do_taint is false, + * assume that PL_tainted can never be true */ +#define TARGu(u, do_taint) \ + STMT_START { \ + UV TARGu_uv = u; \ + if (LIKELY( \ + ((SvFLAGS(TARG) & (SVTYPEMASK|SVf_THINKFIRST)) == SVt_IV) \ + & (do_taint ? !TAINT_get : 1) \ + & (TARGu_uv <= (UV)IV_MAX))) \ + { \ + /* Cheap SvIOK_only(). \ + * Assert that flags which SvIOK_only() would test or \ + * clear can't be set, because we're SVt_IV */ \ + assert(!(SvFLAGS(TARG) & \ + (SVf_OOK|SVf_UTF8|(SVf_OK & ~(SVf_IOK|SVp_IOK))))); \ + SvFLAGS(TARG) |= (SVf_IOK|SVp_IOK); \ + /* SvIV_set() where sv_any points to head */ \ + TARG->sv_u.svu_iv = TARGu_uv; \ + } \ + else \ + sv_setuv_mg(targ, TARGu_uv); \ + } STMT_END + +/* set TARG to the NV value n. If do_taint is false, + * assume that PL_tainted can never be true */ +#define TARGn(n, do_taint) \ + STMT_START { \ + NV TARGn_nv = n; \ + if (LIKELY( \ + ((SvFLAGS(TARG) & (SVTYPEMASK|SVf_THINKFIRST)) == SVt_NV) \ + & (do_taint ? !TAINT_get : 1))) \ + { \ + /* Cheap SvNOK_only(). \ + * Assert that flags which SvNOK_only() would test or \ + * clear can't be set, because we're SVt_NV */ \ + assert(!(SvFLAGS(TARG) & \ + (SVf_OOK|SVf_UTF8|(SVf_OK & ~(SVf_NOK|SVp_NOK))))); \ + SvFLAGS(TARG) |= (SVf_NOK|SVp_NOK); \ + SvNV_set(TARG, TARGn_nv); \ + } \ + else \ + sv_setnv_mg(targ, TARGn_nv); \ + } STMT_END + #define PUSHs(s) (*++sp = (s)) #define PUSHTARG STMT_START { SvSETMAGIC(TARG); PUSHs(TARG); } STMT_END #define PUSHp(p,l) STMT_START { sv_setpvn(TARG, (p), (l)); PUSHTARG; } STMT_END -#define PUSHn(n) STMT_START { sv_setnv(TARG, (NV)(n)); PUSHTARG; } STMT_END -#define PUSHi(i) STMT_START { sv_setiv(TARG, (IV)(i)); PUSHTARG; } STMT_END -#define PUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); PUSHTARG; } STMT_END +#define PUSHn(n) STMT_START { TARGn(n,1); PUSHs(TARG); } STMT_END +#define PUSHi(i) STMT_START { TARGi(i,1); PUSHs(TARG); } STMT_END +#define PUSHu(u) STMT_START { TARGu(u,1); PUSHs(TARG); } STMT_END #define XPUSHs(s) STMT_START { EXTEND(sp,1); *++sp = (s); } STMT_END #define XPUSHTARG STMT_START { SvSETMAGIC(TARG); XPUSHs(TARG); } STMT_END #define XPUSHp(p,l) STMT_START { sv_setpvn(TARG, (p), (l)); XPUSHTARG; } STMT_END -#define XPUSHn(n) STMT_START { sv_setnv(TARG, (NV)(n)); XPUSHTARG; } STMT_END -#define XPUSHi(i) STMT_START { sv_setiv(TARG, (IV)(i)); XPUSHTARG; } STMT_END -#define XPUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); XPUSHTARG; } STMT_END +#define XPUSHn(n) STMT_START { TARGn(n,1); XPUSHs(TARG); } STMT_END +#define XPUSHi(i) STMT_START { TARGi(i,1); XPUSHs(TARG); } STMT_END +#define XPUSHu(u) STMT_START { TARGu(u,1); XPUSHs(TARG); } STMT_END #define XPUSHundef STMT_START { SvOK_off(TARG); XPUSHs(TARG); } STMT_END #define mPUSHs(s) PUSHs(sv_2mortal(s)) @@ -403,9 +469,9 @@ Does not use C. See also C>, C> and C>. #define SETs(s) (*sp = s) #define SETTARG STMT_START { SvSETMAGIC(TARG); SETs(TARG); } STMT_END #define SETp(p,l) STMT_START { sv_setpvn(TARG, (p), (l)); SETTARG; } STMT_END -#define SETn(n) STMT_START { sv_setnv(TARG, (NV)(n)); SETTARG; } STMT_END -#define SETi(i) STMT_START { sv_setiv(TARG, (IV)(i)); SETTARG; } STMT_END -#define SETu(u) STMT_START { sv_setuv(TARG, (UV)(u)); SETTARG; } STMT_END +#define SETn(n) STMT_START { TARGn(n,1); SETs(TARG); } STMT_END +#define SETi(i) STMT_START { TARGi(i,1); SETs(TARG); } STMT_END +#define SETu(u) STMT_START { TARGu(u,1); SETs(TARG); } STMT_END #define dTOPss SV *sv = TOPs #define dPOPss SV *sv = POPs