diff options
author | Richard Leach <richardleach@users.noreply.github.com> | 2022-08-06 21:55:28 +0000 |
---|---|---|
committer | Richard Leach <richardleach@users.noreply.github.com> | 2022-09-07 20:27:27 +0100 |
commit | aafefcb90183e1d6ef62d9e1ccc1fae7fcdf9c8e (patch) | |
tree | b870aefc05d58e8daabe190802e82f35047d32c7 /peep.c | |
parent | ec18fac0008c98267fc560f7023d1d11703ed66d (diff) | |
download | perl-aafefcb90183e1d6ef62d9e1ccc1fae7fcdf9c8e.tar.gz |
OP_AELEMFASTLEX_STORE - combined sassign/aelemfast_lex
This commit introduces a new OP to replace simple cases of OP_SASSIGN
and OP_AELEMFAST_LEX. (Similar concept to GH #19943)
For example, `my @ary; $ary[0] = "boo"` is currently implemented as:
7 <2> sassign vKS/2 ->8
5 <$> const[PV "boo"] s ->6
- <1> ex-aelem sKRM*/2 ->7
6 <0> aelemfast_lex[@ary:1,2] sRM ->7
- <0> ex-const s ->-
But now will be turned into:
6 <1> aelemfastlex_store[@ary:1,2] vKS ->7
5 <$> const(PV "boo") s ->6
- <1> ex-aelem sKRM*/2 ->6
- <0> ex-aelemfast_lex sRM ->6
- <0> ex-const s ->-
This is intended to be a transparent performance optimization.
It should be applicable for RHS optrees of varying complexity.
Diffstat (limited to 'peep.c')
-rw-r--r-- | peep.c | 49 |
1 files changed, 49 insertions, 0 deletions
@@ -3951,6 +3951,55 @@ Perl_rpeep(pTHX_ OP *o) /* NULL the previous op ptrs, so rpeep can continue */ oldoldop = NULL; oldop = NULL; } + + /* Combine a simple SASSIGN OP with an AELEMFAST_LEX lvalue + * into a single OP. This optimization covers arbitrarily + * complicated RHS OP trees. */ + + if (!(o->op_private & (OPpASSIGN_BACKWARDS|OPpASSIGN_CV_TO_GV)) + && (lval->op_type == OP_NULL) && (lval->op_private == 2) && + (cBINOPx(lval)->op_first->op_type == OP_AELEMFAST_LEX) && + ((I8)(cBINOPx(lval)->op_first->op_private) >= 0) + ) { + OP * lex = cBINOPx(lval)->op_first; + /* SASSIGN's bitfield flags, such as op_moresib and + * op_slabbed, will be carried over unchanged. */ + OpTYPE_set(o, OP_AELEMFASTLEX_STORE); + + /* Explicitly craft the new OP's op_flags, carrying + * some bits over from the SASSIGN */ + o->op_flags = ( + OPf_KIDS | OPf_STACKED | + (o->op_flags & (OPf_WANT|OPf_PARENS)) + ); + + /* Copy the AELEMFAST_LEX op->private, which contains + * the key index. */ + o->op_private = lex->op_private; + + /* Take the targ from the AELEMFAST_LEX */ + o->op_targ = lex->op_targ; lex->op_targ = 0; + + assert(oldop->op_type == OP_AELEMFAST_LEX); + /* oldoldop can be arbitrarily deep in the RHS OP tree */ + oldoldop->op_next = o; + + /* Even when (rhs != oldoldop), rhs might still have a + * relevant op_next ptr to lex. (Updating it here can + * also cause other ops in the RHS to get the desired + * op_next pointer, presumably thanks to the finalizer.) + * This is definitely truewhen rhs is OP_NULL with a + * LOGOP kid (e.g. orassign). There may be other cases. */ + if (rhs->op_next == lex) + rhs->op_next = o; + + /* Now null-out the AELEMFAST_LEX */ + op_null(lex); + + /* NULL the previous op ptrs, so rpeep can continue */ + oldop = oldoldop; oldoldop = NULL; + } + break; } |