Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[dotnet] Stub in an NQP Optimizer. Only one optimization at the momen…
…t, which strips off return handlers from routines if they're never used (something we can statically detect in NQP).
- Loading branch information
Showing
1 changed file
with
93 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| # This is a very basic optimizer for NQP. It works over the PAST tree. It makes | ||
| # various assumptions that are NQP-specific. In particular (please update this | ||
| # list if you add optimizations): | ||
| # * There is no eval that can see outer lexicals. | ||
| # * All returning is done through a PAST::Op node with :pasttype('return') | ||
|
|
||
| class NQPOptimizer { | ||
| method optimize($past) { | ||
| # Set up a block stack with a fake block. | ||
| my @*BLOCK_STACK; | ||
| @*BLOCK_STACK.push(PAST::Block.new()); | ||
|
|
||
| # Run the optimizer. | ||
| optimizer($past); | ||
|
|
||
| $past | ||
| } | ||
| } | ||
|
|
||
| our multi optimizer(PAST::Block $block) { | ||
| # Mark that our parent block has an inner block and unshift ourself | ||
| # onto the block stack. | ||
| annotate(@*BLOCK_STACK[0], 'has_nested_blocks', 1); | ||
| @*BLOCK_STACK.unshift($block); | ||
|
|
||
| # Go through the block and call the optimizer on everything in it. | ||
| for @($block) { | ||
| optimizer($_); | ||
| } | ||
|
|
||
| # If we have a return handler but nothing marked it used, toss it. | ||
| if $block.control && !get_annotation($block, 'return_used') { | ||
| $block.control(''); | ||
| } | ||
|
|
||
| # Remove this block from the block stack. | ||
| @*BLOCK_STACK.shift(); | ||
| } | ||
|
|
||
| our multi optimizer(PAST::Stmts $stmts) { | ||
| # Need to do nothing other than loop through children. | ||
| for @($stmts) { | ||
| optimizer($_); | ||
| } | ||
| } | ||
|
|
||
| our multi optimizer(PAST::Op $op) { | ||
| # Need to visit the children. | ||
| for @($op) { | ||
| optimizer($_); | ||
| } | ||
|
|
||
| # If it's a return node, go find something with a return handler | ||
| # and annotate that the return is used. | ||
| if $op.pasttype eq 'return' { | ||
| for @*BLOCK_STACK { | ||
| if $_.control { | ||
| annotate($_, 'return_used', 1); | ||
| last; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| our multi optimizer(PAST::Var $var) { | ||
| # May need to visit the viviself. | ||
| if $var.viviself ~~ PAST::Node { | ||
| optimizer($var.viviself); | ||
| } | ||
| } | ||
|
|
||
| our multi optimizer(PAST::Val $stmts) { | ||
| # Nothing to do at all :-) | ||
| } | ||
|
|
||
| our multi sub optimizer($any) { | ||
| if pir::isa($any, 'String') || pir::isa($any, 'Integer') || pir::isa($any, 'Float') { | ||
| # Literals - nothing to do. | ||
| } | ||
| else { | ||
| pir::die("optimizer() is missing a candidate for " ~ pir::typeof__SP($any) ~ "(" ~ $any ~ ")"); | ||
| } | ||
| } | ||
|
|
||
| # Annotates a node with a given note. | ||
| sub annotate($node, $key, $value) { | ||
| $node{'nqp_opt_' ~ $key} := $value; | ||
| } | ||
|
|
||
| # Gets an annotation made on a node. | ||
| sub get_annotation($node, $key) { | ||
| $node{'nqp_opt_' ~ $key} | ||
| } |