a25e7e25fb23454b4c090e4f1553bfa665280bb1
[p5sagit/p5-mst-13.2.git] / B / CC.pm
1 #      CC.pm
2 #
3 #      Copyright (c) 1996 Malcolm Beattie
4 #
5 #      You may distribute under the terms of either the GNU General Public
6 #      License or the Artistic License, as specified in the README file.
7 #
8 package B::CC;
9 use strict;
10 use B qw(main_start main_root class comppadlist peekop svref_2object ad
11         timing_info);
12 use B::C qw(push_decl init_init push_init save_unused_subs objsym
13             output_all output_boilerplate output_main);
14 use B::Bblock qw(find_leaders);
15 use B::Stackobj qw(:types :flags);
16
17 # These should probably be elsewhere
18 # Flags for $op->flags
19 sub OPf_LIST () { 1 }
20 sub OPf_KNOW () { 2 }
21 sub OPf_MOD () { 32 }
22 sub OPf_STACKED () { 64 }
23 sub OPf_SPECIAL () { 128 }
24 # op-specific flags for $op->private 
25 sub OPpASSIGN_BACKWARDS () { 64 }
26 sub OPpLVAL_INTRO () { 128 }
27 sub OPpDEREF_AV () { 32 }
28 sub OPpDEREF_HV () { 64 }
29 sub OPpFLIP_LINENUM () { 64 }
30 sub G_ARRAY () { 1 }
31 # cop.h
32 sub CXt_NULL () { 0 }
33 sub CXt_SUB () { 1 }
34 sub CXt_EVAL () { 2 }
35 sub CXt_LOOP () { 3 }
36 sub CXt_SUBST () { 4 }
37 sub CXt_BLOCK () { 5 }
38
39 my %done;               # hash keyed by $$op of leaders of basic blocks
40                         # which have already been done.
41 my $leaders;            # ref to hash of basic block leaders. Keys are $$op
42                         # addresses, values are the $op objects themselves.
43 my @bblock_todo;        # list of leaders of basic blocks that need visiting
44                         # sometime.
45 my @cc_todo;            # list of tuples defining what PP code needs to be
46                         # saved (e.g. CV, main or PMOP repl code). Each tuple
47                         # is [$name, $root, $start, @padlist]. PMOP repl code
48                         # tuples inherit padlist.
49 my @stack;              # shadows perl's stack when contents are known.
50                         # Values are objects derived from class B::Stackobj
51 my @pad;                # Lexicals in current pad as Stackobj-derived objects
52 my @padlist;            # Copy of current padlist so PMOP repl code can find it
53 my @cxstack;            # Shadows the (compile-time) cxstack for next,last,redo
54 my $jmpbuf_ix = 0;      # Next free index for dynamically allocated jmpbufs
55 my %constobj;           # OP_CONST constants as Stackobj-derived objects
56                         # keyed by ad($sv).
57 my $need_freetmps = 0;  # We may postpone FREETMPS to the end of each basic
58                         # block or even to the end of each loop of blocks,
59                         # depending on optimisation options.
60 my $know_op = 0;        # Set when C variable op already holds the right op
61                         # (from an immediately preceding DOOP(ppname)).
62 my $errors = 0;         # Number of errors encountered
63 my %skip_stack;         # Hash of PP names which don't need write_back_stack
64 my %skip_lexicals;      # Hash of PP names which don't need write_back_lexicals
65 my %skip_invalidate;    # Hash of PP names which don't need invalidate_lexicals
66 my %ignore_op;          # Hash of ops which do nothing except returning op_next
67
68 BEGIN {
69     foreach (qw(pp_scalar pp_regcmaybe pp_lineseq pp_scope pp_null)) {
70         $ignore_op{$_} = 1;
71     }
72 }
73
74 my @unused_sub_packages; # list of packages (given by -u options) to search
75                          # explicitly and save every sub we find there, even
76                          # if apparently unused (could be only referenced from
77                          # an eval "" or from a $SIG{FOO} = "bar").
78
79 my ($module_name);
80 my ($debug_op, $debug_stack, $debug_cxstack, $debug_pad, $debug_runtime,
81     $debug_shadow, $debug_queue, $debug_lineno, $debug_timings);
82
83 # Optimisation options. On the command line, use hyphens instead of
84 # underscores for compatibility with gcc-style options. We use
85 # underscores here because they are OK in (strict) barewords.
86 my ($freetmps_each_bblock, $freetmps_each_loop, $omit_taint);
87 my %optimise = (freetmps_each_bblock    => \$freetmps_each_bblock,
88                 freetmps_each_loop      => \$freetmps_each_loop,
89                 omit_taint              => \$omit_taint);
90
91 # Could rewrite push_runtime() and output_runtime() to use a
92 # temporary file if memory is at a premium.
93 my $ppname;             # name of current fake PP function
94 my $runtime_list_ref;
95 my $declare_ref;        # Hash ref keyed by C variable type of declarations.
96
97 my @pp_list;            # list of [$ppname, $runtime_list_ref, $declare_ref]
98                         # tuples to be written out.
99
100 sub init_hash { map { $_ => 1 } @_ }
101
102 #
103 # Initialise the hashes for the default PP functions where we can avoid
104 # either write_back_stack, write_back_lexicals or invalidate_lexicals.
105 #
106 %skip_lexicals = init_hash qw(pp_enter pp_enterloop);
107 %skip_invalidate = init_hash qw(pp_enter pp_enterloop);
108
109 sub debug {
110     if ($debug_runtime) {
111         warn(@_);
112     } else {
113         runtime(map { chomp; "/* $_ */"} @_);
114     }
115 }
116
117 sub declare {
118     my ($type, $var) = @_;
119     push(@{$declare_ref->{$type}}, $var);
120 }
121
122 sub push_runtime {
123     push(@$runtime_list_ref, @_);
124     warn join("\n", @_) . "\n" if $debug_runtime;
125 }
126
127 sub save_runtime {
128     push(@pp_list, [$ppname, $runtime_list_ref, $declare_ref]);
129 }
130
131 sub output_runtime {
132     my $ppdata;
133     print qq(#include "cc_runtime.h"\n);
134     foreach $ppdata (@pp_list) {
135         my ($name, $runtime, $declare) = @$ppdata;
136         print "\nstatic\nPP($name)\n{\n";
137         my ($type, $varlist, $line);
138         while (($type, $varlist) = each %$declare) {
139             print "\t$type ", join(", ", @$varlist), ";\n";
140         }
141         foreach $line (@$runtime) {
142             print $line, "\n";
143         }
144         print "}\n";
145     }
146 }
147
148 sub runtime {
149     my $line;
150     foreach $line (@_) {
151         push_runtime("\t$line");
152     }
153 }
154
155 sub init_pp {
156     $ppname = shift;
157     $runtime_list_ref = [];
158     $declare_ref = {};
159     runtime("dSP;");
160     declare("I32", "oldsave");
161     declare("SV", "**svp");
162     map { declare("SV", "*$_") } qw(sv src dst left right);
163     declare("MAGIC", "*mg");
164     push_decl("static OP * $ppname _((ARGSproto));");
165     debug "init_pp: $ppname\n" if $debug_queue;
166 }
167
168 # Initialise runtime_callback function for Stackobj class
169 BEGIN { B::Stackobj::set_callback(\&runtime) }
170
171 # Initialise saveoptree_callback for B::C class
172 sub cc_queue {
173     my ($name, $root, $start, @pl) = @_;
174     debug "cc_queue: name $name, root $root, start $start, padlist (@pl)\n"
175         if $debug_queue;
176     if ($name eq "*ignore*") {
177         $name = 0;
178     } else {
179         push(@cc_todo, [$name, $root, $start, (@pl ? @pl : @padlist)]);
180     }
181     my $fakeop = new B::FAKEOP ("next" => 0, sibling => 0, ppaddr => $name);
182     $start = $fakeop->save;
183     debug "cc_queue: name $name returns $start\n" if $debug_queue;
184     return $start;
185 }
186 BEGIN { B::C::set_callback(\&cc_queue) }
187
188 sub valid_int { $_[0]->{flags} & VALID_INT }
189 sub valid_double { $_[0]->{flags} & VALID_DOUBLE }
190 sub valid_numeric { $_[0]->{flags} & (VALID_INT | VALID_DOUBLE) }
191 sub valid_sv { $_[0]->{flags} & VALID_SV }
192
193 sub top_int { @stack ? $stack[-1]->as_int : "TOPi" }
194 sub top_double { @stack ? $stack[-1]->as_double : "TOPn" }
195 sub top_numeric { @stack ? $stack[-1]->as_numeric : "TOPn" }
196 sub top_sv { @stack ? $stack[-1]->as_sv : "TOPs" }
197 sub top_bool { @stack ? $stack[-1]->as_numeric : "SvTRUE(TOPs)" }
198
199 sub pop_int { @stack ? (pop @stack)->as_int : "POPi" }
200 sub pop_double { @stack ? (pop @stack)->as_double : "POPn" }
201 sub pop_numeric { @stack ? (pop @stack)->as_numeric : "POPn" }
202 sub pop_sv { @stack ? (pop @stack)->as_sv : "POPs" }
203 sub pop_bool {
204     if (@stack) {
205         return ((pop @stack)->as_numeric);
206     } else {
207         # Careful: POPs has an auto-decrement and SvTRUE evaluates
208         # its argument more than once.
209         runtime("sv = POPs;");
210         return "SvTRUE(sv)";
211     }
212 }
213
214 sub write_back_lexicals {
215     my $avoid = shift || 0;
216     debug "write_back_lexicals($avoid) called from @{[(caller(1))[3]]}\n"
217         if $debug_shadow;
218     my $lex;
219     foreach $lex (@pad) {
220         next unless ref($lex);
221         $lex->write_back unless $lex->{flags} & $avoid;
222     }
223 }
224
225 sub write_back_stack {
226     my $obj;
227     return unless @stack;
228     runtime(sprintf("EXTEND(sp, %d);", scalar(@stack)));
229     foreach $obj (@stack) {
230         runtime(sprintf("PUSHs((SV*)%s);", $obj->as_sv));
231     }
232     @stack = ();
233 }
234
235 sub invalidate_lexicals {
236     my $avoid = shift || 0;
237     debug "invalidate_lexicals($avoid) called from @{[(caller(1))[3]]}\n"
238         if $debug_shadow;
239     my $lex;
240     foreach $lex (@pad) {
241         next unless ref($lex);
242         $lex->invalidate unless $lex->{flags} & $avoid;
243     }
244 }
245
246 sub reload_lexicals {
247     my $lex;
248     foreach $lex (@pad) {
249         next unless ref($lex);
250         my $type = $lex->{type};
251         if ($type == T_INT) {
252             $lex->as_int;
253         } elsif ($type == T_DOUBLE) {
254             $lex->as_double;
255         } else {
256             $lex->as_sv;
257         }
258     }
259 }
260
261 {
262     package B::Pseudoreg;
263     #
264     # This class allocates pseudo-registers (OK, so they're C variables).
265     #
266     my %alloc;          # Keyed by variable name. A value of 1 means the
267                         # variable has been declared. A value of 2 means
268                         # it's in use.
269     
270     sub new_scope { %alloc = () }
271     
272     sub new ($$$) {
273         my ($class, $type, $prefix) = @_;
274         my ($ptr, $i, $varname, $status, $obj);
275         $prefix =~ s/^(\**)//;
276         $ptr = $1;
277         $i = 0;
278         do {
279             $varname = "$prefix$i";
280             $status = $alloc{$varname};
281         } while $status == 2;
282         if ($status != 1) {
283             # Not declared yet
284             B::CC::declare($type, "$ptr$varname");
285             $alloc{$varname} = 2;       # declared and in use
286         }
287         $obj = bless \$varname, $class;
288         return $obj;
289     }
290     sub DESTROY {
291         my $obj = shift;
292         $alloc{$$obj} = 1; # no longer in use but still declared
293     }
294 }
295 {
296     package B::Shadow;
297     #
298     # This class gives a standard API for a perl object to shadow a
299     # C variable and only generate reloads/write-backs when necessary.
300     #
301     # Use $obj->load($foo) instead of runtime("shadowed_c_var = foo").
302     # Use $obj->write_back whenever shadowed_c_var needs to be up to date.
303     # Use $obj->invalidate whenever an unknown function may have
304     # set shadow itself.
305
306     sub new {
307         my ($class, $write_back) = @_;
308         # Object fields are perl shadow variable, validity flag
309         # (for *C* variable) and callback sub for write_back
310         # (passed perl shadow variable as argument).
311         bless [undef, 1, $write_back], $class;
312     }
313     sub load {
314         my ($obj, $newval) = @_;
315         $obj->[1] = 0;          # C variable no longer valid
316         $obj->[0] = $newval;
317     }
318     sub write_back {
319         my $obj = shift;
320         if (!($obj->[1])) {
321             $obj->[1] = 1;      # C variable will now be valid
322             &{$obj->[2]}($obj->[0]);
323         }
324     }
325     sub invalidate { $_[0]->[1] = 0 } # force C variable to be invalid
326 }
327 my $curcop = new B::Shadow (sub {
328     my $opsym = shift->save;
329     runtime("curcop = (COP*)$opsym;");
330 });
331
332 #
333 # Context stack shadowing. Mimics stuff in pp_ctl.c, cop.h and so on.
334 #
335 sub dopoptoloop {
336     my $cxix = $#cxstack;
337     while ($cxix >= 0 && $cxstack[$cxix]->{type} != CXt_LOOP) {
338         $cxix--;
339     }
340     debug "dopoptoloop: returning $cxix" if $debug_cxstack;
341     return $cxix;
342 }
343
344 sub dopoptolabel {
345     my $label = shift;
346     my $cxix = $#cxstack;
347     while ($cxix >= 0 && $cxstack[$cxix]->{type} != CXt_LOOP
348            && $cxstack[$cxix]->{label} ne $label) {
349         $cxix--;
350     }
351     debug "dopoptolabel: returning $cxix" if $debug_cxstack;
352     return $cxix;
353 }
354
355 sub error {
356     my $format = shift;
357     my $file = $curcop->[0]->filegv->SV->PV;
358     my $line = $curcop->[0]->line;
359     $errors++;
360     if (@_) {
361         warn sprintf("%s:%d: $format\n", $file, $line, @_);
362     } else {
363         warn sprintf("%s:%d: %s\n", $file, $line, $format);
364     }
365 }
366
367 #
368 # Load pad takes (the elements of) a PADLIST as arguments and loads
369 # up @pad with Stackobj-derived objects which represent those lexicals.
370 # If/when perl itself can generate type information (my int $foo) then
371 # we'll take advantage of that here. Until then, we'll use various hacks
372 # to tell the compiler when we want a lexical to be a particular type
373 # or to be a register.
374 #
375 sub load_pad {
376     my ($namelistav, $valuelistav) = @_;
377     @padlist = @_;
378     my @namelist = $namelistav->ARRAY;
379     my @valuelist = $valuelistav->ARRAY;
380     my $ix;
381     @pad = ();
382     debug "load_pad: $#namelist names, $#valuelist values\n" if $debug_pad;
383     # Temporary lexicals don't get named so it's possible for @valuelist
384     # to be strictly longer than @namelist. We count $ix up to the end of
385     # @valuelist but index into @namelist for the name. Any temporaries which
386     # run off the end of @namelist will make $namesv undefined and we treat
387     # that the same as having an explicit SPECIAL sv_undef object in @namelist.
388     # [XXX If/when @_ becomes a lexical, we must start at 0 here.]
389     for ($ix = 1; $ix < @valuelist; $ix++) {
390         my $namesv = $namelist[$ix];
391         my $type = T_UNKNOWN;
392         my $flags = 0;
393         my $name = "tmp$ix";
394         my $class = class($namesv);
395         if (!defined($namesv) || $class eq "SPECIAL") {
396             # temporaries have &sv_undef instead of a PVNV for a name
397             $flags = VALID_SV|TEMPORARY|REGISTER;
398         } else {
399             if ($namesv->PV =~ /^\$(.*)_([di])(r?)$/) {
400                 $name = $1;
401                 if ($2 eq "i") {
402                     $type = T_INT;
403                     $flags = VALID_SV|VALID_INT;
404                 } elsif ($2 eq "d") {
405                     $type = T_DOUBLE;
406                     $flags = VALID_SV|VALID_DOUBLE;
407                 }
408                 $flags |= REGISTER if $3;
409             }
410         }
411         $pad[$ix] = new B::Stackobj::Padsv ($type, $flags, $ix,
412                                             "i_$name", "d_$name");
413         declare("IV", $type == T_INT ? "i_$name = 0" : "i_$name");
414         declare("double", $type == T_DOUBLE ? "d_$name = 0" : "d_$name");
415         debug sprintf("curpad[$ix] = %s\n", $pad[$ix]->peek) if $debug_pad;
416     }
417 }
418
419 #
420 # Debugging stuff
421 #
422 sub peek_stack { sprintf "stack = %s\n", join(" ", map($_->minipeek, @stack)) }
423
424 #
425 # OP stuff
426 #
427
428 sub label {
429     my $op = shift;
430     # XXX Preserve original label name for "real" labels?
431     return sprintf("lab_%x", $$op);
432 }
433
434 sub write_label {
435     my $op = shift;
436     push_runtime(sprintf("  %s:", label($op)));
437 }
438
439 sub loadop {
440     my $op = shift;
441     my $opsym = $op->save;
442     runtime("op = $opsym;") unless $know_op;
443     return $opsym;
444 }
445
446 sub doop {
447     my $op = shift;
448     my $ppname = $op->ppaddr;
449     my $sym = loadop($op);
450     runtime("DOOP($ppname);");
451     $know_op = 1;
452     return $sym;
453 }
454
455 sub gimme {
456     my $op = shift;
457     my $flags = $op->flags;
458     return (($flags & OPf_KNOW) ? ($flags & OPf_LIST) : "dowantarray()");
459 }
460
461 #
462 # Code generation for PP code
463 #
464
465 sub pp_null {
466     my $op = shift;
467     return $op->next;
468 }
469
470 sub pp_stub {
471     my $op = shift;
472     my $gimme = gimme($op);
473     if ($gimme != 1) {
474         # XXX Change to push a constant sv_undef Stackobj onto @stack
475         write_back_stack();
476         runtime("if ($gimme != G_ARRAY) XPUSHs(&sv_undef);");
477     }
478     return $op->next;
479 }
480
481 sub pp_unstack {
482     my $op = shift;
483     @stack = ();
484     runtime("PP_UNSTACK;");
485     return $op->next;
486 }
487
488 sub pp_and {
489     my $op = shift;
490     my $next = $op->next;
491     reload_lexicals();
492     unshift(@bblock_todo, $next);
493     if (@stack >= 1) {
494         my $bool = pop_bool();
495         write_back_stack();
496         runtime(sprintf("if (!$bool) goto %s;", label($next)));
497     } else {
498         runtime(sprintf("if (!%s) goto %s;", top_bool(), label($next)),
499                 "*sp--;");
500     }
501     return $op->other;
502 }
503             
504 sub pp_or {
505     my $op = shift;
506     my $next = $op->next;
507     reload_lexicals();
508     unshift(@bblock_todo, $next);
509     if (@stack >= 1) {
510         my $obj = pop @stack;
511         write_back_stack();
512         runtime(sprintf("if (%s) { XPUSHs(%s); goto %s; }",
513                         $obj->as_numeric, $obj->as_sv, label($next)));
514     } else {
515         runtime(sprintf("if (%s) goto %s;", top_bool(), label($next)),
516                 "*sp--;");
517     }
518     return $op->other;
519 }
520             
521 sub pp_cond_expr {
522     my $op = shift;
523     my $false = $op->false;
524     unshift(@bblock_todo, $false);
525     reload_lexicals();
526     my $bool = pop_bool();
527     write_back_stack();
528     runtime(sprintf("if (!$bool) goto %s;", label($false)));
529     return $op->true;
530 }
531             
532
533 sub pp_padsv {
534     my $op = shift;
535     my $ix = $op->targ;
536     push(@stack, $pad[$ix]);
537     if ($op->flags & OPf_MOD) {
538         my $private = $op->private;
539         if ($private & OPpLVAL_INTRO) {
540             runtime("SAVECLEARSV(curpad[$ix]);");
541         } elsif ($private & (OPpDEREF_HV|OPpDEREF_AV)) {
542             loadop($op);
543             runtime("provide_ref(op, curpad[$ix]);");
544             $pad[$ix]->invalidate;
545         }
546     }
547     return $op->next;
548 }
549
550 sub pp_const {
551     my $op = shift;
552     my $sv = $op->sv;
553     my $obj = $constobj{ad($sv)};
554     if (!defined($obj)) {
555         $obj = $constobj{ad($sv)} = new B::Stackobj::Const ($sv);
556     }
557     push(@stack, $obj);
558     return $op->next;
559 }
560
561 sub pp_nextstate {
562     my $op = shift;
563     $curcop->load($op);
564     @stack = ();
565     debug(sprintf("%s:%d\n", $op->filegv->SV->PV, $op->line)) if $debug_lineno;
566     runtime("TAINT_NOT;") unless $omit_taint;
567     runtime("sp = stack_base + cxstack[cxstack_ix].blk_oldsp;");
568     if ($freetmps_each_bblock || $freetmps_each_loop) {
569         $need_freetmps = 1;
570     } else {
571         runtime("FREETMPS;");
572     }
573     return $op->next;
574 }
575
576 sub pp_dbstate {
577     my $op = shift;
578     $curcop->invalidate; # XXX?
579     return default_pp($op);
580 }
581
582 sub pp_rv2gv { $curcop->write_back; default_pp(@_) }
583 sub pp_bless { $curcop->write_back; default_pp(@_) }
584 sub pp_repeat { $curcop->write_back; default_pp(@_) }
585 # The following subs need $curcop->write_back if we decide to support arybase:
586 # pp_pos, pp_substr, pp_index, pp_rindex, pp_aslice, pp_lslice, pp_splice
587 sub pp_sort { $curcop->write_back; default_pp(@_) }
588 sub pp_caller { $curcop->write_back; default_pp(@_) }
589 sub pp_reset { $curcop->write_back; default_pp(@_) }
590
591 sub pp_gv {
592     my $op = shift;
593     my $gvsym = $op->gv->save;
594     write_back_stack();
595     runtime("XPUSHs((SV*)$gvsym);");
596     return $op->next;
597 }
598
599 sub pp_gvsv {
600     my $op = shift;
601     my $gvsym = $op->gv->save;
602     write_back_stack();
603     if ($op->private & OPpLVAL_INTRO) {
604         runtime("XPUSHs(save_scalar($gvsym));");
605     } else {
606         runtime("XPUSHs(GvSV($gvsym));");
607     }
608     return $op->next;
609 }
610
611 sub pp_aelemfast {
612     my $op = shift;
613     my $gvsym = $op->gv->save;
614     my $ix = $op->private;
615     my $flag = $op->flags & OPf_MOD;
616     write_back_stack();
617     runtime("svp = av_fetch(GvAV($gvsym), $ix, $flag);",
618             "PUSHs(svp ? *svp : &sv_undef);");
619     return $op->next;
620 }
621
622 sub int_binop {
623     my ($op, $operator) = @_;
624     if ($op->flags & OPf_STACKED) {
625         my $right = pop_int();
626         if (@stack >= 1) {
627             my $left = top_int();
628             $stack[-1]->set_int(&$operator($left, $right));
629         } else {
630             runtime(sprintf("sv_setiv(TOPs, %s);",&$operator("TOPi", $right)));
631         }
632     } else {
633         my $targ = $pad[$op->targ];
634         my $right = new B::Pseudoreg ("IV", "riv");
635         my $left = new B::Pseudoreg ("IV", "liv");
636         runtime(sprintf("$$right = %s; $$left = %s;", pop_int(), pop_int));
637         $targ->set_int(&$operator($$left, $$right));
638         push(@stack, $targ);
639     }
640     return $op->next;
641 }
642
643 sub INTS_CLOSED () { 0x1 }
644 sub INT_RESULT () { 0x2 }
645 sub NUMERIC_RESULT () { 0x4 }
646
647 sub numeric_binop {
648     my ($op, $operator, $flags) = @_;
649     my $force_int = 0;
650     $force_int ||= ($flags & INT_RESULT);
651     $force_int ||= ($flags & INTS_CLOSED && @stack >= 2
652                     && valid_int($stack[-2]) && valid_int($stack[-1]));
653     if ($op->flags & OPf_STACKED) {
654         my $right = pop_numeric();
655         if (@stack >= 1) {
656             my $left = top_numeric();
657             if ($force_int) {
658                 $stack[-1]->set_int(&$operator($left, $right));
659             } else {
660                 $stack[-1]->set_numeric(&$operator($left, $right));
661             }
662         } else {
663             if ($force_int) {
664                 runtime(sprintf("sv_setiv(TOPs, %s);",
665                                 &$operator("TOPi", $right)));
666             } else {
667                 runtime(sprintf("sv_setnv(TOPs, %s);",
668                                 &$operator("TOPn", $right)));
669             }
670         }
671     } else {
672         my $targ = $pad[$op->targ];
673         $force_int ||= ($targ->{type} == T_INT);
674         if ($force_int) {
675             my $right = new B::Pseudoreg ("IV", "riv");
676             my $left = new B::Pseudoreg ("IV", "liv");
677             runtime(sprintf("$$right = %s; $$left = %s;",
678                             pop_numeric(), pop_numeric));
679             $targ->set_int(&$operator($$left, $$right));
680         } else {
681             my $right = new B::Pseudoreg ("double", "rnv");
682             my $left = new B::Pseudoreg ("double", "lnv");
683             runtime(sprintf("$$right = %s; $$left = %s;",
684                             pop_numeric(), pop_numeric));
685             $targ->set_numeric(&$operator($$left, $$right));
686         }
687         push(@stack, $targ);
688     }
689     return $op->next;
690 }
691
692 sub sv_binop {
693     my ($op, $operator, $flags) = @_;
694     if ($op->flags & OPf_STACKED) {
695         my $right = pop_sv();
696         if (@stack >= 1) {
697             my $left = top_sv();
698             if ($flags & INT_RESULT) {
699                 $stack[-1]->set_int(&$operator($left, $right));
700             } elsif ($flags & NUMERIC_RESULT) {
701                 $stack[-1]->set_numeric(&$operator($left, $right));
702             } else {
703                 # XXX Does this work?
704                 runtime(sprintf("sv_setsv($left, %s);",
705                                 &$operator($left, $right)));
706                 $stack[-1]->invalidate;
707             }
708         } else {
709             my $f;
710             if ($flags & INT_RESULT) {
711                 $f = "sv_setiv";
712             } elsif ($flags & NUMERIC_RESULT) {
713                 $f = "sv_setnv";
714             } else {
715                 $f = "sv_setsv";
716             }
717             runtime(sprintf("%s(TOPs, %s);", $f, &$operator("TOPs", $right)));
718         }
719     } else {
720         my $targ = $pad[$op->targ];
721         runtime(sprintf("right = %s; left = %s;", pop_sv(), pop_sv));
722         if ($flags & INT_RESULT) {
723             $targ->set_int(&$operator("left", "right"));
724         } elsif ($flags & NUMERIC_RESULT) {
725             $targ->set_numeric(&$operator("left", "right"));
726         } else {
727             # XXX Does this work?
728             runtime(sprintf("sv_setsv(%s, %s);",
729                             $targ->as_sv, &$operator("left", "right")));
730             $targ->invalidate;
731         }
732         push(@stack, $targ);
733     }
734     return $op->next;
735 }
736     
737 sub bool_int_binop {
738     my ($op, $operator) = @_;
739     my $right = new B::Pseudoreg ("IV", "riv");
740     my $left = new B::Pseudoreg ("IV", "liv");
741     runtime(sprintf("$$right = %s; $$left = %s;", pop_int(), pop_int()));
742     my $bool = new B::Stackobj::Bool (new B::Pseudoreg ("int", "b"));
743     $bool->set_int(&$operator($$left, $$right));
744     push(@stack, $bool);
745     return $op->next;
746 }
747
748 sub bool_numeric_binop {
749     my ($op, $operator) = @_;
750     my $right = new B::Pseudoreg ("double", "rnv");
751     my $left = new B::Pseudoreg ("double", "lnv");
752     runtime(sprintf("$$right = %s; $$left = %s;",
753                     pop_numeric(), pop_numeric()));
754     my $bool = new B::Stackobj::Bool (new B::Pseudoreg ("int", "b"));
755     $bool->set_numeric(&$operator($$left, $$right));
756     push(@stack, $bool);
757     return $op->next;
758 }
759
760 sub bool_sv_binop {
761     my ($op, $operator) = @_;
762     runtime(sprintf("right = %s; left = %s;", pop_sv(), pop_sv()));
763     my $bool = new B::Stackobj::Bool (new B::Pseudoreg ("int", "b"));
764     $bool->set_numeric(&$operator("left", "right"));
765     push(@stack, $bool);
766     return $op->next;
767 }
768
769 sub infix_op {
770     my $opname = shift;
771     return sub { "$_[0] $opname $_[1]" }
772 }
773
774 sub prefix_op {
775     my $opname = shift;
776     return sub { sprintf("%s(%s)", $opname, join(", ", @_)) }
777 }
778
779 BEGIN {
780     my $plus_op = infix_op("+");
781     my $minus_op = infix_op("-");
782     my $multiply_op = infix_op("*");
783     my $divide_op = infix_op("/");
784     my $modulo_op = infix_op("%");
785     my $lshift_op = infix_op("<<");
786     my $rshift_op = infix_op("<<");
787     my $ncmp_op = sub { "($_[0] > $_[1] ? 1 : ($_[0] < $_[1]) ? -1 : 0)" };
788     my $scmp_op = prefix_op("sv_cmp");
789     my $seq_op = prefix_op("sv_eq");
790     my $sne_op = prefix_op("!sv_eq");
791     my $slt_op = sub { "sv_cmp($_[0], $_[1]) < 0" };
792     my $sgt_op = sub { "sv_cmp($_[0], $_[1]) > 0" };
793     my $sle_op = sub { "sv_cmp($_[0], $_[1]) <= 0" };
794     my $sge_op = sub { "sv_cmp($_[0], $_[1]) >= 0" };
795     my $eq_op = infix_op("==");
796     my $ne_op = infix_op("!=");
797     my $lt_op = infix_op("<");
798     my $gt_op = infix_op(">");
799     my $le_op = infix_op("<=");
800     my $ge_op = infix_op(">=");
801
802     #
803     # XXX The standard perl PP code has extra handling for
804     # some special case arguments of these operators.
805     #
806     sub pp_add { numeric_binop($_[0], $plus_op, INTS_CLOSED) }
807     sub pp_subtract { numeric_binop($_[0], $minus_op, INTS_CLOSED) }
808     sub pp_multiply { numeric_binop($_[0], $multiply_op, INTS_CLOSED) }
809     sub pp_divide { numeric_binop($_[0], $divide_op) }
810     sub pp_modulo { int_binop($_[0], $modulo_op) } # differs from perl's
811     sub pp_ncmp { numeric_binop($_[0], $ncmp_op, INT_RESULT) }
812
813     sub pp_left_shift { int_binop($_[0], $lshift_op) }
814     sub pp_right_shift { int_binop($_[0], $rshift_op) }
815     sub pp_i_add { int_binop($_[0], $plus_op) }
816     sub pp_i_subtract { int_binop($_[0], $minus_op) }
817     sub pp_i_multiply { int_binop($_[0], $multiply_op) }
818     sub pp_i_divide { int_binop($_[0], $divide_op) }
819     sub pp_i_modulo { int_binop($_[0], $modulo_op) }
820
821     sub pp_eq { bool_numeric_binop($_[0], $eq_op) }
822     sub pp_ne { bool_numeric_binop($_[0], $ne_op) }
823     sub pp_lt { bool_numeric_binop($_[0], $lt_op) }
824     sub pp_gt { bool_numeric_binop($_[0], $gt_op) }
825     sub pp_le { bool_numeric_binop($_[0], $le_op) }
826     sub pp_ge { bool_numeric_binop($_[0], $ge_op) }
827
828     sub pp_i_eq { bool_int_binop($_[0], $eq_op) }
829     sub pp_i_ne { bool_int_binop($_[0], $ne_op) }
830     sub pp_i_lt { bool_int_binop($_[0], $lt_op) }
831     sub pp_i_gt { bool_int_binop($_[0], $gt_op) }
832     sub pp_i_le { bool_int_binop($_[0], $le_op) }
833     sub pp_i_ge { bool_int_binop($_[0], $ge_op) }
834
835     sub pp_scmp { sv_binop($_[0], $scmp_op, INT_RESULT) }
836     sub pp_slt { bool_sv_binop($_[0], $slt_op) }
837     sub pp_sgt { bool_sv_binop($_[0], $sgt_op) }
838     sub pp_sle { bool_sv_binop($_[0], $sle_op) }
839     sub pp_sge { bool_sv_binop($_[0], $sge_op) }
840     sub pp_seq { bool_sv_binop($_[0], $seq_op) }
841     sub pp_sne { bool_sv_binop($_[0], $sne_op) }
842 }
843
844
845 sub pp_sassign {
846     my $op = shift;
847     my $backwards = $op->private & OPpASSIGN_BACKWARDS;
848     my ($dst, $src);
849     if (@stack >= 2) {
850         $dst = pop @stack;
851         $src = pop @stack;
852         ($src, $dst) = ($dst, $src) if $backwards;
853         my $type = $src->{type};
854         if ($type == T_INT) {
855             $dst->set_int($src->as_int);
856         } elsif ($type == T_DOUBLE) {
857             $dst->set_numeric($src->as_numeric);
858         } else {
859             $dst->set_sv($src->as_sv);
860         }
861         push(@stack, $dst);
862     } elsif (@stack == 1) {
863         if ($backwards) {
864             my $src = pop @stack;
865             my $type = $src->{type};
866             runtime("if (tainting && tainted) TAINT_NOT;");
867             if ($type == T_INT) {
868                 runtime sprintf("sv_setiv(TOPs, %s);", $src->as_int);
869             } elsif ($type == T_DOUBLE) {
870                 runtime sprintf("sv_setnv(TOPs, %s);", $src->as_double);
871             } else {
872                 runtime sprintf("sv_setsv(TOPs, %s);", $src->as_sv);
873             }
874             runtime("SvSETMAGIC(TOPs);");
875         } else {
876             my $dst = pop @stack;
877             my $type = $dst->{type};
878             runtime("sv = POPs;");
879             runtime("MAYBE_TAINT_SASSIGN_SRC(sv);");
880             if ($type == T_INT) {
881                 $dst->set_int("SvIV(sv)");
882             } elsif ($type == T_DOUBLE) {
883                 $dst->set_double("SvNV(sv)");
884             } else {
885                 runtime("SvSetSV($dst->{sv}, sv);");
886                 $dst->invalidate;
887             }
888         }
889     } else {
890         if ($backwards) {
891             runtime("src = POPs; dst = TOPs;");
892         } else {
893             runtime("dst = POPs; src = TOPs;");
894         }
895         runtime("MAYBE_TAINT_SASSIGN_SRC(src);",
896                 "SvSetSV(dst, src);",
897                 "SvSETMAGIC(dst);",
898                 "SETs(dst);");
899     }
900     return $op->next;
901 }
902
903 sub pp_preinc {
904     my $op = shift;
905     if (@stack >= 1) {
906         my $obj = $stack[-1];
907         my $type = $obj->{type};
908         if ($type == T_INT || $type == T_DOUBLE) {
909             $obj->set_int($obj->as_int . " + 1");
910         } else {
911             runtime sprintf("PP_PREINC(%s);", $obj->as_sv);
912             $obj->invalidate();
913         }
914     } else {
915         runtime sprintf("PP_PREINC(TOPs);");
916     }
917     return $op->next;
918 }
919
920 sub pp_pushmark {
921     my $op = shift;
922     write_back_stack();
923     runtime("PUSHMARK(sp);");
924     return $op->next;
925 }
926
927 sub pp_list {
928     my $op = shift;
929     write_back_stack();
930     my $gimme = gimme($op);
931     if ($gimme == 1) { # sic
932         runtime("POPMARK;"); # need this even though not a "full" pp_list
933     } else {
934         runtime("PP_LIST($gimme);");
935     }
936     return $op->next;
937 }
938
939 sub pp_entersub {
940     my $op = shift;
941     write_back_lexicals(REGISTER|TEMPORARY);
942     write_back_stack();
943     my $sym = doop($op);
944     runtime("if (op != ($sym)->op_next) op = (*op->op_ppaddr)();");
945     runtime("SPAGAIN;");
946     $know_op = 0;
947     invalidate_lexicals(REGISTER|TEMPORARY);
948     return $op->next;
949 }
950
951 sub doeval {
952     my $op = shift;
953     $curcop->write_back;
954     write_back_lexicals(REGISTER|TEMPORARY);
955     write_back_stack();
956     my $sym = loadop($op);
957     my $ppaddr = $op->ppaddr;
958     runtime("PP_EVAL($ppaddr, ($sym)->op_next);");
959     $know_op = 1;
960     invalidate_lexicals(REGISTER|TEMPORARY);
961     return $op->next;
962 }
963
964 sub pp_entereval { doeval(@_) }
965 sub pp_require { doeval(@_) }
966 sub pp_dofile { doeval(@_) }
967
968 sub pp_entertry {
969     my $op = shift;
970     $curcop->write_back;
971     write_back_lexicals(REGISTER|TEMPORARY);
972     write_back_stack();
973     my $sym = doop($op);
974     my $jmpbuf = sprintf("jmpbuf%d", $jmpbuf_ix++);
975     declare("Sigjmp_buf", $jmpbuf);
976     runtime(sprintf("PP_ENTERTRY(%s,%s);", $jmpbuf, label($op->other->next)));
977     invalidate_lexicals(REGISTER|TEMPORARY);
978     return $op->next;
979 }
980
981 sub pp_grepstart {
982     my $op = shift;
983     if ($need_freetmps && $freetmps_each_loop) {
984         runtime("FREETMPS;"); # otherwise the grepwhile loop messes things up
985         $need_freetmps = 0;
986     }
987     write_back_stack();
988     doop($op);
989     return $op->next->other;
990 }
991
992 sub pp_mapstart {
993     my $op = shift;
994     if ($need_freetmps && $freetmps_each_loop) {
995         runtime("FREETMPS;"); # otherwise the mapwhile loop messes things up
996         $need_freetmps = 0;
997     }
998     write_back_stack();
999     doop($op);
1000     return $op->next->other;
1001 }
1002
1003 sub pp_grepwhile {
1004     my $op = shift;
1005     my $next = $op->next;
1006     unshift(@bblock_todo, $next);
1007     write_back_lexicals();
1008     write_back_stack();
1009     my $sym = doop($op);
1010     # pp_grepwhile can return either op_next or op_other and we need to
1011     # be able to distinguish the two at runtime. Since it's possible for
1012     # both ops to be "inlined", the fields could both be zero. To get
1013     # around that, we hack op_next to be our own op (purely because we
1014     # know it's a non-NULL pointer and can't be the same as op_other).
1015     push_init("((LOGOP*)$sym)->op_next = $sym;");
1016     runtime(sprintf("if (op == ($sym)->op_next) goto %s;", label($next)));
1017     $know_op = 0;
1018     return $op->other;
1019 }
1020
1021 sub pp_mapwhile {
1022     pp_grepwhile(@_);
1023 }
1024
1025 sub pp_return {
1026     my $op = shift;
1027     write_back_lexicals(REGISTER|TEMPORARY);
1028     write_back_stack();
1029     doop($op);
1030     runtime("PUTBACK;", "return 0;");
1031     $know_op = 0;
1032     return $op->next;
1033 }
1034
1035 sub nyi {
1036     my $op = shift;
1037     warn sprintf("%s not yet implemented properly\n", $op->ppaddr);
1038     return default_pp($op);
1039 }
1040
1041 sub pp_range {
1042     my $op = shift;
1043     my $flags = $op->flags;
1044     if (!($flags & OPf_KNOW)) {
1045         error("context of range unknown at compile-time");
1046     }
1047     write_back_lexicals();
1048     write_back_stack();
1049     if (!($flags & OPf_LIST)) {
1050         # We need to save our UNOP structure since pp_flop uses
1051         # it to find and adjust out targ. We don't need it ourselves.
1052         $op->save;
1053         runtime sprintf("if (SvTRUE(curpad[%d])) goto %s;",
1054                         $op->targ, label($op->false));
1055         unshift(@bblock_todo, $op->false);
1056     }
1057     return $op->true;
1058 }
1059
1060 sub pp_flip {
1061     my $op = shift;
1062     my $flags = $op->flags;
1063     if (!($flags & OPf_KNOW)) {
1064         error("context of flip unknown at compile-time");
1065     }
1066     if ($flags & OPf_LIST) {
1067         return $op->first->false;
1068     }
1069     write_back_lexicals();
1070     write_back_stack();
1071     # We need to save our UNOP structure since pp_flop uses
1072     # it to find and adjust out targ. We don't need it ourselves.
1073     $op->save;
1074     my $ix = $op->targ;
1075     my $rangeix = $op->first->targ;
1076     runtime(($op->private & OPpFLIP_LINENUM) ?
1077             "if (last_in_gv && SvIV(TOPs) == IoLINES(GvIOp(last_in_gv))) {"
1078           : "if (SvTRUE(TOPs)) {");
1079     runtime("\tsv_setiv(curpad[$rangeix], 1);");
1080     if ($op->flags & OPf_SPECIAL) {
1081         runtime("sv_setiv(curpad[$ix], 1);");
1082     } else {
1083         runtime("\tsv_setiv(curpad[$ix], 0);",
1084                 "\tsp--;",
1085                 sprintf("\tgoto %s;", label($op->first->false)));
1086     }
1087     runtime("}",
1088           qq{sv_setpv(curpad[$ix], "");},
1089             "SETs(curpad[$ix]);");
1090     $know_op = 0;
1091     return $op->next;
1092 }
1093
1094 sub pp_flop {
1095     my $op = shift;
1096     default_pp($op);
1097     $know_op = 0;
1098     return $op->next;
1099 }
1100
1101 sub enterloop {
1102     my $op = shift;
1103     my $nextop = $op->nextop;
1104     my $lastop = $op->lastop;
1105     my $redoop = $op->redoop;
1106     $curcop->write_back;
1107     debug "enterloop: pushing on cxstack" if $debug_cxstack;
1108     push(@cxstack, {
1109         type => CXt_LOOP,
1110         op => $op,
1111         "label" => $curcop->[0]->label,
1112         nextop => $nextop,
1113         lastop => $lastop,
1114         redoop => $redoop
1115     });
1116     $nextop->save;
1117     $lastop->save;
1118     $redoop->save;
1119     return default_pp($op);
1120 }
1121
1122 sub pp_enterloop { enterloop(@_) }
1123 sub pp_enteriter { enterloop(@_) }
1124
1125 sub pp_leaveloop {
1126     my $op = shift;
1127     if (!@cxstack) {
1128         die "panic: leaveloop";
1129     }
1130     debug "leaveloop: popping from cxstack" if $debug_cxstack;
1131     pop(@cxstack);
1132     return default_pp($op);
1133 }
1134
1135 sub pp_next {
1136     my $op = shift;
1137     my $cxix;
1138     if ($op->flags & OPf_SPECIAL) {
1139         $cxix = dopoptoloop();
1140         if ($cxix < 0) {
1141             error('"next" used outside loop');
1142             return $op->next; # ignore the op
1143         }
1144     } else {
1145         $cxix = dopoptolabel($op->pv);
1146         if ($cxix < 0) {
1147             error('Label not found at compile time for "next %s"', $op->pv);
1148             return $op->next; # ignore the op
1149         }
1150     }
1151     default_pp($op);
1152     my $nextop = $cxstack[$cxix]->{nextop};
1153     push(@bblock_todo, $nextop);
1154     runtime(sprintf("goto %s;", label($nextop)));
1155     return $op->next;
1156 }
1157
1158 sub pp_redo {
1159     my $op = shift;
1160     my $cxix;
1161     if ($op->flags & OPf_SPECIAL) {
1162         $cxix = dopoptoloop();
1163         if ($cxix < 0) {
1164             error('"redo" used outside loop');
1165             return $op->next; # ignore the op
1166         }
1167     } else {
1168         $cxix = dopoptolabel($op->pv);
1169         if ($cxix < 0) {
1170             error('Label not found at compile time for "redo %s"', $op->pv);
1171             return $op->next; # ignore the op
1172         }
1173     }
1174     default_pp($op);
1175     my $redoop = $cxstack[$cxix]->{redoop};
1176     push(@bblock_todo, $redoop);
1177     runtime(sprintf("goto %s;", label($redoop)));
1178     return $op->next;
1179 }
1180
1181 sub pp_last {
1182     my $op = shift;
1183     my $cxix;
1184     if ($op->flags & OPf_SPECIAL) {
1185         $cxix = dopoptoloop();
1186         if ($cxix < 0) {
1187             error('"last" used outside loop');
1188             return $op->next; # ignore the op
1189         }
1190     } else {
1191         $cxix = dopoptolabel($op->pv);
1192         if ($cxix < 0) {
1193             error('Label not found at compile time for "last %s"', $op->pv);
1194             return $op->next; # ignore the op
1195         }
1196         # XXX Add support for "last" to leave non-loop blocks
1197         if ($cxstack[$cxix]->{type} != CXt_LOOP) {
1198             error('Use of "last" for non-loop blocks is not yet implemented');
1199             return $op->next; # ignore the op
1200         }
1201     }
1202     default_pp($op);
1203     my $lastop = $cxstack[$cxix]->{lastop}->next;
1204     push(@bblock_todo, $lastop);
1205     runtime(sprintf("goto %s;", label($lastop)));
1206     return $op->next;
1207 }
1208
1209 sub pp_subst {
1210     my $op = shift;
1211     write_back_lexicals();
1212     write_back_stack();
1213     my $sym = doop($op);
1214     my $replroot = $op->pmreplroot;
1215     if (ad($replroot)) {
1216         runtime sprintf("if (op == ((PMOP*)(%s))->op_pmreplroot) goto %s;",
1217                         $sym, label($replroot));
1218         $op->pmreplstart->save;
1219         push(@bblock_todo, $replroot);
1220     }
1221     invalidate_lexicals();
1222     return $op->next;
1223 }
1224
1225 sub pp_substcont {
1226     my $op = shift;
1227     write_back_lexicals();
1228     write_back_stack();
1229     doop($op);
1230     my $pmop = $op->other;
1231     my $pmopsym = objsym($pmop);
1232     runtime sprintf("if (op == ((PMOP*)(%s))->op_pmreplstart) goto %s;",
1233                     $pmopsym, label($pmop->pmreplstart));
1234     invalidate_lexicals();
1235     return $pmop->next;
1236 }
1237
1238 sub default_pp {
1239     my $op = shift;
1240     my $ppname = $op->ppaddr;
1241     write_back_lexicals() unless $skip_lexicals{$ppname};
1242     write_back_stack() unless $skip_stack{$ppname};
1243     doop($op);
1244     # XXX If the only way that ops can write to a TEMPORARY lexical is
1245     # when it's named in $op->targ then we could call
1246     # invalidate_lexicals(TEMPORARY) and avoid having to write back all
1247     # the temporaries. For now, we'll play it safe and write back the lot.
1248     invalidate_lexicals() unless $skip_invalidate{$ppname};
1249     return $op->next;
1250 }
1251
1252 sub compile_op {
1253     my $op = shift;
1254     my $ppname = $op->ppaddr;
1255     if (exists $ignore_op{$ppname}) {
1256         return $op->next;
1257     }
1258     debug peek_stack() if $debug_stack;
1259     if ($debug_op) {
1260         debug sprintf("%s [%s]\n",
1261                      peekop($op),
1262                      $op->flags & OPf_STACKED ? "OPf_STACKED" : $op->targ);
1263     }
1264     no strict 'refs';
1265     if (defined(&$ppname)) {
1266         $know_op = 0;
1267         return &$ppname($op);
1268     } else {
1269         return default_pp($op);
1270     }
1271 }
1272
1273 sub compile_bblock {
1274     my $op = shift;
1275     #warn "compile_bblock: ", peekop($op), "\n"; # debug
1276     write_label($op);
1277     $know_op = 0;
1278     do {
1279         $op = compile_op($op);
1280     } while (defined($op) && $$op && !exists($leaders->{$$op}));
1281     write_back_stack(); # boo hoo: big loss
1282     reload_lexicals();
1283     return $op;
1284 }
1285
1286 sub cc {
1287     my ($name, $root, $start, @padlist) = @_;
1288     my $op;
1289     init_pp($name);
1290     load_pad(@padlist);
1291     B::Pseudoreg->new_scope;
1292     @cxstack = ();
1293     if ($debug_timings) {
1294         warn sprintf("Basic block analysis at %s\n", timing_info);
1295     }
1296     $leaders = find_leaders($root, $start);
1297     @bblock_todo = ($start, values %$leaders);
1298     if ($debug_timings) {
1299         warn sprintf("Compilation at %s\n", timing_info);
1300     }
1301     while (@bblock_todo) {
1302         $op = shift @bblock_todo;
1303         #warn sprintf("Considering basic block %s\n", peekop($op)); # debug
1304         next if !defined($op) || !$$op || $done{$$op};
1305         #warn "...compiling it\n"; # debug
1306         do {
1307             $done{$$op} = 1;
1308             $op = compile_bblock($op);
1309             if ($need_freetmps && $freetmps_each_bblock) {
1310                 runtime("FREETMPS;");
1311                 $need_freetmps = 0;
1312             }
1313         } while defined($op) && $$op && !$done{$$op};
1314         if ($need_freetmps && $freetmps_each_loop) {
1315             runtime("FREETMPS;");
1316             $need_freetmps = 0;
1317         }
1318         if (!$$op) {
1319             runtime("PUTBACK;", "return 0;");
1320         } elsif ($done{$$op}) {
1321             runtime(sprintf("goto %s;", label($op)));
1322         }
1323     }
1324     if ($debug_timings) {
1325         warn sprintf("Saving runtime at %s\n", timing_info);
1326     }
1327     save_runtime();
1328 }
1329
1330 sub cc_recurse {
1331     my $ccinfo;
1332     my $start;
1333     $start = cc_queue(@_) if @_;
1334     while ($ccinfo = shift @cc_todo) {
1335         cc(@$ccinfo);
1336     }
1337     return $start;
1338 }    
1339
1340 sub cc_obj {
1341     my ($name, $cvref) = @_;
1342     my $cv = svref_2object($cvref);
1343     my @padlist = $cv->PADLIST->ARRAY;
1344     my $curpad_sym = $padlist[1]->save;
1345     cc_recurse($name, $cv->ROOT, $cv->START, @padlist);
1346 }
1347
1348 sub cc_main {
1349     my @comppadlist = comppadlist->ARRAY;
1350     my $curpad_sym = $comppadlist[1]->save;
1351     my $start = cc_recurse("pp_main", main_root, main_start, @comppadlist);
1352     if (@unused_sub_packages) {
1353         save_unused_subs(@unused_sub_packages);
1354         # That only queues them. Now we need to generate code for them.
1355         cc_recurse();
1356     }
1357     return if $errors;
1358     push_init(sprintf("main_root = sym_%x;", ad(main_root)),
1359               "main_start = $start;",
1360               "curpad = AvARRAY($curpad_sym);");
1361     output_boilerplate();
1362     print "\n";
1363     output_all("perl_init");
1364     output_runtime();
1365     print "\n";
1366     output_main();
1367     if ($debug_timings) {
1368         warn sprintf("Done at %s\n", timing_info);
1369     }
1370 }
1371
1372 sub compile {
1373     my @options = @_;
1374     my ($option, $opt, $arg);
1375   OPTION:
1376     while ($option = shift @options) {
1377         if ($option =~ /^-(.)(.*)/) {
1378             $opt = $1;
1379             $arg = $2;
1380         } else {
1381             unshift @options, $option;
1382             last OPTION;
1383         }
1384         if ($opt eq "-" && $arg eq "-") {
1385             shift @options;
1386             last OPTION;
1387         } elsif ($opt eq "o") {
1388             $arg ||= shift @options;
1389             open(STDOUT, ">$arg") or return "$arg: $!\n";
1390         } elsif ($opt eq "n") {
1391             $arg ||= shift @options;
1392             $module_name = $arg;
1393         } elsif ($opt eq "u") {
1394             $arg ||= shift @options;
1395             push(@unused_sub_packages, $arg);
1396         } elsif ($opt eq "f") {
1397             $arg ||= shift @options;
1398             my $value = $arg !~ s/^no-//;
1399             $arg =~ s/-/_/g;
1400             my $ref = $optimise{$arg};
1401             if (defined($ref)) {
1402                 $$ref = $value;
1403             } else {
1404                 warn qq(ignoring unknown optimisation option "$arg"\n);
1405             }
1406         } elsif ($opt eq "O") {
1407             $arg = 1 if $arg eq "";
1408             my $ref;
1409             foreach $ref (values %optimise) {
1410                 $$ref = 0;
1411             }
1412             if ($arg >= 2) {
1413                 $freetmps_each_loop = 1;
1414             }
1415             if ($arg >= 1) {
1416                 $freetmps_each_bblock = 1 unless $freetmps_each_loop;
1417             }
1418         } elsif ($opt eq "D") {
1419             $arg ||= shift @options;
1420             foreach $arg (split(//, $arg)) {
1421                 if ($arg eq "o") {
1422                     B->debug(1);
1423                 } elsif ($arg eq "O") {
1424                     $debug_op = 1;
1425                 } elsif ($arg eq "s") {
1426                     $debug_stack = 1;
1427                 } elsif ($arg eq "c") {
1428                     $debug_cxstack = 1;
1429                 } elsif ($arg eq "p") {
1430                     $debug_pad = 1;
1431                 } elsif ($arg eq "r") {
1432                     $debug_runtime = 1;
1433                 } elsif ($arg eq "S") {
1434                     $debug_shadow = 1;
1435                 } elsif ($arg eq "q") {
1436                     $debug_queue = 1;
1437                 } elsif ($arg eq "l") {
1438                     $debug_lineno = 1;
1439                 } elsif ($arg eq "t") {
1440                     $debug_timings = 1;
1441                 }
1442             }
1443         }
1444     }
1445     init_init();
1446     if (@options) {
1447         return sub {
1448             my ($objname, $ppname);
1449             foreach $objname (@options) {
1450                 $objname = "main::$objname" unless $objname =~ /::/;
1451                 ($ppname = $objname) =~ s/^.*?:://;
1452                 eval "cc_obj(qq(pp_sub_$ppname), \\&$objname)";
1453                 die "cc_obj(qq(pp_sub_$ppname, \\&$objname) failed: $@" if $@;
1454                 return if $errors;
1455             }
1456             output_boilerplate();
1457             print "\n";
1458             output_all($module_name || "init_module");
1459             output_runtime();
1460         }
1461     } else {
1462         return sub { cc_main() };
1463     }
1464 }
1465
1466 1;