Implement --prune-unreachable-routines.

This commit is contained in:
Chris Pressey 2019-10-22 09:41:30 +01:00
parent 1df6941b01
commit 3d88226058
6 changed files with 71 additions and 14 deletions

View File

@ -11,6 +11,9 @@ History of SixtyPical
* A routine can be declared `preserved`, which prevents a
compiler from omitting it from the final executable, even
if it determines it is not called by any other routine.
* Added `--prune-unreachable-routines` option, which causes
the compiler to in fact omit routines determined to be
unreachable as described above.
* The `dcc6502-adapter` test adapter was updated to conform
to the output of the latest version of `dcc6502`.

12
TODO.md
View File

@ -95,13 +95,6 @@ As long as the routine has consistent type context every place it exits, that sh
Currently the `if` generator is not smart enough to avoid generating silly
jump instructions. (See the Fallthru tests.) Improve it.
### Dead code removal
Once we have a call graph we can omit routines that we're sure aren't called.
This would let us use include-files and standard-libraries nicely: any
routines they define, but that you don't use, don't get included.
Implementation
--------------
@ -110,6 +103,11 @@ Implementation
For analysis errors, there is a line number, but it's the line of the routine
after the routine in which the analysis error occurred. Fix this.
### Libraries
Now that we have dead-code removal, establish some libraries of reusable
routines.
Blue-skying
-----------

View File

@ -19,6 +19,7 @@ import traceback
from sixtypical.symtab import SymbolTable
from sixtypical.parser import Parser, merge_programs
from sixtypical.analyzer import Analyzer
from sixtypical.callgraph import construct_callgraph, prune_unreachable_routines
from sixtypical.outputter import outputter_class_for
from sixtypical.compiler import Compiler
@ -47,13 +48,14 @@ def process_input_files(filenames, options):
analyzer.analyze_program(program)
finally:
if options.dump_exit_contexts:
sys.stdout.write(json.dumps(analyzer.exit_contexts_map, indent=4, sort_keys=True, separators=(',', ':')))
sys.stdout.write(json.dumps(analyzer.exit_contexts_map, indent=4, sort_keys=True, separators=(',', ': ')))
sys.stdout.write("\n")
callgraph = construct_callgraph(program)
if options.dump_callgraph:
from sixtypical.callgraph import construct_callgraph
graph = construct_callgraph(program)
sys.stdout.write(json.dumps(graph, indent=4, sort_keys=True, separators=(',', ': ')))
sys.stdout.write(json.dumps(callgraph, indent=4, sort_keys=True, separators=(',', ': ')))
if options.prune_unreachable_routines:
program = prune_unreachable_routines(program, callgraph)
compilation_roster = None
if options.optimize_fallthru:
@ -166,6 +168,12 @@ if __name__ == '__main__':
action="store_true",
help="Dump the ordered fallthru map, in JSON, to stdout after analyzing the program."
)
argparser.add_argument(
"--prune-unreachable-routines",
action="store_true",
help="Omit code for unreachable routines (as determined by the callgraph) "
"from the final output."
)
argparser.add_argument(
"--dump-callgraph",
action="store_true",

View File

@ -1,3 +1,4 @@
from sixtypical.ast import Program
from sixtypical.model import RoutineType, VectorType
@ -58,3 +59,9 @@ def construct_callgraph(program):
mark_as_reachable(graph, routine.name)
return graph
def prune_unreachable_routines(program, callgraph):
return Program(1, defns=program.defns, routines=[
r for r in program.routines if callgraph[r.name].get('reachable', False)
])

View File

@ -183,3 +183,41 @@ reachable.
= ]
= }
= }
-> Tests for functionality "Compile SixtyPical program with unreachable routine removal"
Basic test for actually removing unreachable routines from the resulting
executable when compiling SixtyPical programs.
| define main routine outputs a trashes z, n
| {
| ld a, 100
| }
|
| define other1 routine
| {
| call other2
| }
|
| define other2 routine
| {
| call other1
| }
= $080D LDA #$64
= $080F RTS
Test that marking routine as `preserved` preserves it in the output.
| define main routine outputs a trashes z, n
| {
| ld a, 100
| }
|
| define other preserved routine outputs a trashes z, n
| {
| ld a, 5
| }
= $080D LDA #$64
= $080F RTS
= $0810 LDA #$05
= $0812 RTS

View File

@ -13,11 +13,14 @@ implementation, `sixtypical`, that is going to implement these functionalities.
-> Functionality "Compile SixtyPical program" is implemented by
-> shell command "bin/sixtypical --output-format=c64-basic-prg --traceback %(test-body-file) --output /tmp/foo && tests/appliances/bin/dcc6502-adapter </tmp/foo"
-> Functionality "Dump fallthru info for SixtyPical program" is implemented by
-> shell command "bin/sixtypical --optimize-fallthru --dump-fallthru-info --analyze-only --traceback %(test-body-file)"
-> Functionality "Dump callgraph info for SixtyPical program" is implemented by
-> shell command "bin/sixtypical --dump-callgraph --analyze-only --traceback %(test-body-file)"
-> Functionality "Compile SixtyPical program with unreachable routine removal" is implemented by
-> shell command "bin/sixtypical --output-format=c64-basic-prg --prune-unreachable-routines --traceback %(test-body-file) --output /tmp/foo && tests/appliances/bin/dcc6502-adapter </tmp/foo"
-> Functionality "Dump fallthru info for SixtyPical program" is implemented by
-> shell command "bin/sixtypical --optimize-fallthru --dump-fallthru-info --analyze-only --traceback %(test-body-file)"
-> Functionality "Compile SixtyPical program with fallthru optimization" is implemented by
-> shell command "bin/sixtypical --output-format=c64-basic-prg --optimize-fallthru --traceback %(test-body-file) --output /tmp/foo && tests/appliances/bin/dcc6502-adapter </tmp/foo"