summaryrefslogtreecommitdiff
path: root/peep.c
diff options
context:
space:
mode:
authorRichard Leach <richardleach@users.noreply.github.com>2022-08-02 21:48:26 +0000
committerRichard Leach <richardleach@users.noreply.github.com>2022-10-24 23:21:17 +0100
commit10a5c9138224597d018843f3b298a928555b67f0 (patch)
tree008b756c7b5f34777576c94ebca07c22ee4c271f /peep.c
parent71a3dd321d7fa8259a22a1ca1e87aa820a8deef2 (diff)
downloadperl-10a5c9138224597d018843f3b298a928555b67f0.tar.gz
OP_EMPTYAVHV - optimized empty ANONLIST/ANONHASH
This commit introduces a new OP to replace cases of OP_ANONLIST and OP_ANONHASH where there are zero elements, which is very common in Perl code. As an example, `my $x = {}` is currently implemented like this: ... 6 <2> sassign vKS/2 ->7 4 <@> anonhash sK* ->5 3 <0> pushmark s ->4 5 <0> padsv[$x:1,2] sRM*/LVINTRO ->6 The pushmark serves no meaningful purpose when there are zero elements and the anonhash, besides undoing the pushmark, performs work that is unnecessary for this special case. The peephole optimizer, which also checks for applicability of a related TARGMY optimization, transforms this example into: ... - <1> ex-sassign vKS/2 ->4 3 <@> emptyavhv[$x:1,2] vK*/LVINTRO,ANONHASH,TARGMY ->4 - <0> ex-pushmark s ->3 - <0> ex-padsv sRM*/LVINTRO ->-
Diffstat (limited to 'peep.c')
-rw-r--r--peep.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/peep.c b/peep.c
index 1319745b9a..0e3a81f019 100644
--- a/peep.c
+++ b/peep.c
@@ -3147,6 +3147,62 @@ Perl_rpeep(pTHX_ OP *o)
}
}
+ /* If the pushmark is associated with an empty anonhash
+ * or anonlist, null out the pushmark and swap in a
+ * specialised op for the parent.
+ * 4 <@> anonhash sK* ->5
+ * 3 <0> pushmark s ->4
+ * becomes:
+ * 3 <@> emptyavhv sK* ->4
+ * - <0> pushmark s ->3
+ */
+ if (!OpHAS_SIBLING(o) && (o->op_next == o->op_sibparent) && (
+ (o->op_next->op_type == OP_ANONHASH) ||
+ (o->op_next->op_type == OP_ANONLIST) ) &&
+ (o->op_next->op_flags & OPf_SPECIAL) ) {
+
+ OP* anon = o->op_next;
+ /* These next two are _potentially_ a padsv and an sassign */
+ OP* padsv = anon->op_next;
+ OP* sassign = (padsv) ? padsv->op_next: NULL;
+
+ anon->op_private = (anon->op_type == OP_ANONLIST) ?
+ 0 : OPpEMPTYAVHV_IS_HV;
+ OpTYPE_set(anon, OP_EMPTYAVHV);
+ op_null(o);
+ o = anon;
+ if (oldop) /* A previous optimization may have NULLED it */
+ oldop->op_next = anon;
+
+ /* Further optimise scalar assignment of an empty anonhash
+ * or anonlist by subsuming the padsv & sassign OPs. */
+ if ((padsv->op_type == OP_PADSV) &&
+ !(padsv->op_private & OPpDEREF) &&
+ sassign && (sassign->op_type == OP_SASSIGN) ){
+
+ /* Take some public flags from the sassign */
+ anon->op_flags = OPf_KIDS | OPf_SPECIAL |
+ (anon->op_flags & OPf_PARENS) |
+ (sassign->op_flags & (OPf_WANT|OPf_PARENS));
+
+ /* Take some private flags from the padsv */
+ anon->op_private |= OPpTARGET_MY |
+ (padsv->op_private & (OPpLVAL_INTRO|OPpPAD_STATE));
+
+ /* Take the targ slot from the padsv*/
+ anon->op_targ = padsv->op_targ;
+ padsv->op_targ = 0;
+
+ /* Clean up */
+ anon->op_next = sassign->op_next;
+ op_null(padsv);
+ op_null(sassign);
+ }
+ break;
+
+ }
+
+
/* Convert a series of PAD ops for my vars plus support into a
* single padrange op. Basically
*