This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
documentation on hooking the peephole optimiser
authorZefram <zefram@fysh.org>
Fri, 10 Sep 2010 19:36:01 +0000 (20:36 +0100)
committerFlorian Ragwitz <rafl@debian.org>
Fri, 10 Sep 2010 19:53:31 +0000 (21:53 +0200)
Signed-off-by: Florian Ragwitz <rafl@debian.org>
[rafl@debian.org: Changed tabs to spaces in perlguts chunks for consistency]

intrpvar.h
pod/perlguts.pod

index ffe59c8..0fd956d 100644 (file)
@@ -171,10 +171,52 @@ PERLVARI(Irehash_seed_set, bool, FALSE)   /* 582 hash initialized? */
 
 PERLVARA(Icolors,6,    char *)         /* from regcomp.c */
 
 
 PERLVARA(Icolors,6,    char *)         /* from regcomp.c */
 
+/*
+=for apidoc Amn|peep_t|PL_peepp
+
+Pointer to the per-subroutine peephole optimiser.  This is a function
+that gets called at the end of compilation of a Perl subroutine (or
+equivalently independent piece of Perl code) to perform fixups of
+some ops and to perform small-scale optimisations.  The function is
+called once for each subroutine that is compiled, and is passed, as sole
+parameter, a pointer to the op that is the entry point to the subroutine.
+It modifies the op tree in place.
+
+The peephole optimiser should never be completely replaced.  Rather,
+add code to it by wrapping the existing optimiser.  The basic way to do
+this can be seen in L<perlguts/Compile pass 3: peephole optimization>.
+If the new code wishes to operate on ops throughout the subroutine's
+structure, rather than just at the top level, it is likely to be more
+convenient to wrap the L</PL_rpeepp> hook.
+
+=cut
+*/
+
 PERLVARI(Ipeepp,       peep_t, MEMBER_TO_FPTR(Perl_peep))
 PERLVARI(Ipeepp,       peep_t, MEMBER_TO_FPTR(Perl_peep))
-                               /* Pointer to per-sub peephole optimizer */
+
+/*
+=for apidoc Amn|peep_t|PL_rpeepp
+
+Pointer to the recursive peephole optimiser.  This is a function
+that gets called at the end of compilation of a Perl subroutine (or
+equivalently independent piece of Perl code) to perform fixups of some
+ops and to perform small-scale optimisations.  The function is called
+once for each chain of ops linked through their C<op_next> fields;
+it is recursively called to handle each side chain.  It is passed, as
+sole parameter, a pointer to the op that is at the head of the chain.
+It modifies the op tree in place.
+
+The peephole optimiser should never be completely replaced.  Rather,
+add code to it by wrapping the existing optimiser.  The basic way to do
+this can be seen in L<perlguts/Compile pass 3: peephole optimization>.
+If the new code wishes to operate only on ops at a subroutine's top level,
+rather than throughout the structure, it is likely to be more convenient
+to wrap the L</PL_peepp> hook.
+
+=cut
+*/
+
 PERLVARI(Irpeepp,      peep_t, MEMBER_TO_FPTR(Perl_rpeep))
 PERLVARI(Irpeepp,      peep_t, MEMBER_TO_FPTR(Perl_rpeep))
-                               /* Pointer to recursive peephole optimizer */
 
 /*
 =for apidoc Amn|Perl_ophook_t|PL_opfreehook
 
 /*
 =for apidoc Amn|Perl_ophook_t|PL_opfreehook
index 62e99bd..5113e51 100644 (file)
@@ -1821,9 +1821,41 @@ of free()ing (i.e. their type is changed to OP_NULL).
 After the compile tree for a subroutine (or for an C<eval> or a file)
 is created, an additional pass over the code is performed. This pass
 is neither top-down or bottom-up, but in the execution order (with
 After the compile tree for a subroutine (or for an C<eval> or a file)
 is created, an additional pass over the code is performed. This pass
 is neither top-down or bottom-up, but in the execution order (with
-additional complications for conditionals).  These optimizations are
-done in the subroutine peep().  Optimizations performed at this stage
-are subject to the same restrictions as in the pass 2.
+additional complications for conditionals).  Optimizations performed
+at this stage are subject to the same restrictions as in the pass 2.
+
+Peephole optimizations are done by calling the function pointed to
+by the global variable C<PL_peepp>.  By default, C<PL_peepp> just
+calls the function pointed to by the global variable C<PL_rpeepp>.
+By default, that performs some basic op fixups and optimisations along
+the execution-order op chain, and recursively calls C<PL_rpeepp> for
+each side chain of ops (resulting from conditionals).  Extensions may
+provide additional optimisations or fixups, hooking into either the
+per-subroutine or recursive stage, like this:
+
+    static peep_t prev_peepp;
+    static void my_peep(pTHX_ OP *o)
+    {
+        /* custom per-subroutine optimisation goes here */
+        prev_peepp(o);
+        /* custom per-subroutine optimisation may also go here */
+    }
+    BOOT:
+        prev_peepp = PL_peepp;
+        PL_peepp = my_peep;
+
+    static peep_t prev_rpeepp;
+    static void my_rpeep(pTHX_ OP *o)
+    {
+        OP *orig_o = o;
+        for(; o; o = o->op_next) {
+            /* custom per-op optimisation goes here */
+        }
+        prev_rpeepp(orig_o);
+    }
+    BOOT:
+        prev_rpeepp = PL_rpeepp;
+        PL_rpeepp = my_rpeep;
 
 =head2 Pluggable runops
 
 
 =head2 Pluggable runops