summaryrefslogtreecommitdiff
path: root/peep.c
diff options
context:
space:
mode:
authorRichard Leach <richardleach@users.noreply.github.com>2022-08-06 21:55:28 +0000
committerRichard Leach <richardleach@users.noreply.github.com>2022-09-07 20:27:27 +0100
commitaafefcb90183e1d6ef62d9e1ccc1fae7fcdf9c8e (patch)
treeb870aefc05d58e8daabe190802e82f35047d32c7 /peep.c
parentec18fac0008c98267fc560f7023d1d11703ed66d (diff)
downloadperl-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.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/peep.c b/peep.c
index 9e558e4186..c18a305dd9 100644
--- a/peep.c
+++ b/peep.c
@@ -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;
}