package B::Bblock;
+
+our $VERSION = '1.00';
+
use Exporter ();
@ISA = "Exporter";
@EXPORT_OK = qw(find_leaders);
use B qw(peekop walkoptree walkoptree_exec
- main_root main_start svref_2object);
-use B::Terse;
+ main_root main_start svref_2object
+ OPf_SPECIAL OPf_STACKED );
+
+use B::Concise qw(concise_cv concise_main set_style_standard);
use strict;
my $bblock;
}
}
+sub remove_sortblock{
+ foreach (keys %$bblock){
+ my $leader=$$bblock{$_};
+ delete $$bblock{$_} if( $leader == 0);
+ }
+}
sub find_leaders {
my ($root, $start) = @_;
$bblock = {};
- mark_leader($start);
- walkoptree($root, "mark_if_leader");
+ mark_leader($start) if ( ref $start ne "B::NULL" );
+ walkoptree($root, "mark_if_leader") if ((ref $root) ne "B::NULL") ;
+ remove_sortblock();
return $bblock;
}
}
printf " %s\n", peekop($lastop);
}
- print "-------\n";
- walkoptree_exec($start, "terse");
}
sub walk_bblocks_obj {
sub B::LOGOP::mark_if_leader {
my $op = shift;
- my $ppaddr = $op->ppaddr;
+ my $opname = $op->name;
mark_leader($op->next);
- if ($ppaddr eq "pp_entertry") {
+ if ($opname eq "entertry") {
mark_leader($op->other->next);
} else {
mark_leader($op->other);
}
}
-sub B::CONDOP::mark_if_leader {
- my $op = shift;
- mark_leader($op->next);
- mark_leader($op->true);
- mark_leader($op->false);
-}
-
sub B::LISTOP::mark_if_leader {
my $op = shift;
- mark_leader($op->first);
+ my $first=$op->first;
+ $first=$first->next while ($first->name eq "null");
+ mark_leader($op->first) unless (exists( $bblock->{$$first}));
mark_leader($op->next);
+ if ($op->name eq "sort" and $op->flags & OPf_SPECIAL
+ and $op->flags & OPf_STACKED){
+ my $root=$op->first->sibling->first;
+ my $leader=$root->first;
+ $bblock->{$$leader} = 0;
+ }
}
sub B::PMOP::mark_if_leader {
my $op = shift;
- if ($op->ppaddr ne "pp_pushre") {
+ if ($op->name ne "pushre") {
my $replroot = $op->pmreplroot;
if ($$replroot) {
mark_leader($replroot);
sub compile {
my @options = @_;
+ B::clearsym();
if (@options) {
return sub {
my $objname;
$objname = "main::$objname" unless $objname =~ /::/;
eval "walk_bblocks_obj(\\&$objname)";
die "walk_bblocks_obj(\\&$objname) failed: $@" if $@;
+ print "-------\n";
+ set_style_standard("terse");
+ eval "concise_cv('exec', \\&$objname)";
+ die "concise_cv('exec', \\&$objname) failed: $@" if $@;
}
}
} else {
- return sub { walk_bblocks(main_root, main_start) };
+ return sub {
+ walk_bblocks(main_root, main_start);
+ print "-------\n";
+ set_style_standard("terse");
+ concise_main("exec");
+ };
}
}
# The ops pointed at by nextop, redoop and lastop->op_next of a LOOP
# The ops pointed at by op_next and op_other of a LOGOP, except
# for pp_entertry which has op_next and op_other->op_next
-# The ops pointed at by op_true and op_false of a CONDOP
# The op pointed at by op_pmreplstart of a PMOP
# The op pointed at by op_other->op_pmreplstart of pp_substcont?
# [The op after a pp_return] Omit
=head1 SYNOPSIS
- perl -MO=Bblock[,OPTIONS] foo.pl
+ # External interface
+ perl -MO=Bblock[,OPTIONS] foo.pl
+
+ # Programmatic API
+ use B::Bblock qw(find_leaders);
+ my $leaders = find_leaders($root_op, $start_op);
=head1 DESCRIPTION
-See F<ext/B/README>.
+This module is used by the B::CC back end. It walks "basic blocks".
+A basic block is a series of operations which is known to execute from
+start to finish, with no possiblity of branching or halting.
+
+It can be used either stand alone or from inside another program.
+
+=for _private
+Somebody who understands the stand-alone options document them, please.
+
+=head2 Functions
+
+=over 4
+
+=item B<find_leaders>
+
+ my $leaders = find_leaders($root_op, $start_op);
+
+Given the root of the op tree and an op from which to start
+processing, it will return a hash ref representing all the ops which
+start a block.
+
+=for _private
+The above description may be somewhat wrong.
+
+The values of %$leaders are the op objects themselves. Keys are $$op
+addresses.
+
+=for _private
+Above cribbed from B::CC's comments. What's a $$op address?
+
+=back
+
=head1 AUTHOR