git @ Cat's Eye Technologies SixtyPical / 1df6941
Callgraph uses reachability. Chris Pressey 3 years ago
4 changed file(s) with 99 addition(s) and 47 deletion(s). Raw diff Collapse all Expand all
44 ----
55
66 * The reference implementation constructs a callgraph and
7 approximates the set of routines which are not called
8 by any other routine, with an eye to omitting them from
9 the final executable.
7 determines the set of routines which are not reachable
8 (directly or indirectly) from `main`, with an eye to
9 omitting them from the final executable.
1010 * A routine can be declared `preserved`, which prevents a
1111 compiler from omitting it from the final executable, even
1212 if it determines it is not called by any other routine.
101101 This would let us use include-files and standard-libraries nicely: any
102102 routines they define, but that you don't use, don't get included.
103103
104 Analyzing the set of possible routines that a vector can take on would help
105 this immensely.
106
107104 Implementation
108105 --------------
109106
55 may be assigned to a location of the given type_ (typically
66 a vector)."""
77 return [r for r in program.routines if RoutineType.executable_types_compatible(r.routine_type, type_)]
8
9
10 def mark_as_reachable(graph, routine_name):
11 node = graph[routine_name]
12 if node.get('reachable', False):
13 return
14 node['reachable'] = True
15 for next_routine_name in node['potentially-calls']:
16 mark_as_reachable(graph, next_routine_name)
817
918
1019 def construct_callgraph(program):
3241 potential_calls = node['potentially-calls']
3342 if routine.name in potential_calls:
3443 potentially_called_by.append(name)
35 if getattr(routine, 'preserved', None) or routine.name == 'main':
36 potentially_called_by.append('*preserved*')
3744 graph[routine.name]['potentially-called-by'] = potentially_called_by
3845
46 # Root set
47
48 root_set = set()
49
50 for routine in program.routines:
51 if getattr(routine, 'preserved', False) or routine.name == 'main':
52 root_set.add(routine)
53
54 # Reachability
55
56 for routine in root_set:
57 mark_as_reachable(graph, routine.name)
58
3959 return graph
1010 -> Tests for functionality "Dump callgraph info for SixtyPical program"
1111
1212 The `main` routine is always called. The thing that it will
13 be called by is the system, but the callgraph analyzer will
14 simply consider it to be "marked as preserved".
13 be called by is the system, but the callgraph analyzer simply
14 considers it to be "reachable".
1515
1616 | define main routine
1717 | {
1818 | }
1919 = {
2020 = "main": {
21 = "potentially-called-by": [
22 = "*preserved*"
23 = ],
24 = "potentially-calls": []
21 = "potentially-called-by": [],
22 = "potentially-calls": [],
23 = "reachable": true
2524 = }
2625 = }
2726
2827 If a routine is called by another routine, this fact will be noted.
28 If it is reachable (directly or indirectly) from `main`, this will
29 be noted as well.
2930
3031 | define main routine
3132 | {
3738 | }
3839 = {
3940 = "main": {
40 = "potentially-called-by": [
41 = "*preserved*"
42 = ],
41 = "potentially-called-by": [],
4342 = "potentially-calls": [
4443 = "other"
45 = ]
44 = ],
45 = "reachable": true
4646 = },
4747 = "other": {
4848 = "potentially-called-by": [
4949 = "main"
5050 = ],
51 = "potentially-calls": []
51 = "potentially-calls": [],
52 = "reachable": true
5253 = }
5354 = }
5455
55 If a routine is not called by another routine, and it is not `main`
56 and it is not explicitly marked as preserved, this absence will be
57 noted, and a compiler or linker will be permitted to omit it from
58 the final executable.
56 If a routine is not potentially called by any other routine that is
57 ultimately potentially called by `main`, this absence will be noted
58 — the routine will not be considered reachable — and a compiler or
59 linker will be permitted to omit it from the final executable.
5960
6061 | define main routine
6162 | {
6667 | }
6768 = {
6869 = "main": {
69 = "potentially-called-by": [
70 = "*preserved*"
71 = ],
72 = "potentially-calls": []
70 = "potentially-called-by": [],
71 = "potentially-calls": [],
72 = "reachable": true
7373 = },
7474 = "other": {
7575 = "potentially-called-by": [],
7878 = }
7979
8080 If a routine is not called by another routine, but it is declared
81 explicitly as `preserved`, then it will not be considered unused,
82 and a compiler or linker will not be permitted to omit it from
83 the final executable. This is useful for interrupt routines and
84 such that really are used by some part of the system, even if not
85 directly by another SixtyPical routine.
81 explicitly as `preserved`, then it will still be considered
82 reachable, and a compiler or linker will not be permitted to omit it
83 from the final executable. This is useful for interrupt routines
84 and such that really are used by some part of the system, even if
85 not directly by another SixtyPical routine.
8686
8787 | define main routine
8888 | {
9393 | }
9494 = {
9595 = "main": {
96 = "potentially-called-by": [
97 = "*preserved*"
98 = ],
99 = "potentially-calls": []
96 = "potentially-called-by": [],
97 = "potentially-calls": [],
98 = "reachable": true
10099 = },
101100 = "other": {
102 = "potentially-called-by": [
103 = "*preserved*"
104 = ],
105 = "potentially-calls": []
101 = "potentially-called-by": [],
102 = "potentially-calls": [],
103 = "reachable": true
106104 = }
107105 = }
108106
109 If two routines potentially call each other, this will be noted,
110 even if nothing else potentially calls either of those routines.
111 This may change in the future.
107 If a routine is called from a preserved routine, that routine is
108 reachable.
109
110 | define main routine
111 | {
112 | }
113 |
114 | define other1 preserved routine
115 | {
116 | call other2
117 | }
118 |
119 | define other2 preserved routine
120 | {
121 | }
122 = {
123 = "main": {
124 = "potentially-called-by": [],
125 = "potentially-calls": [],
126 = "reachable": true
127 = },
128 = "other1": {
129 = "potentially-called-by": [],
130 = "potentially-calls": [
131 = "other2"
132 = ],
133 = "reachable": true
134 = },
135 = "other2": {
136 = "potentially-called-by": [
137 = "other1"
138 = ],
139 = "potentially-calls": [],
140 = "reachable": true
141 = }
142 = }
143
144 If a group of routines potentially call each other, but neither is
145 found to be reachable (directly or indirectly) from `main` or a
146 `preserved` routine, the routines in the group will not be considered
147 reachable.
112148
113149 | define main routine
114150 | {
125161 | }
126162 = {
127163 = "main": {
128 = "potentially-called-by": [
129 = "*preserved*"
130 = ],
131 = "potentially-calls": []
164 = "potentially-called-by": [],
165 = "potentially-calls": [],
166 = "reachable": true
132167 = },
133168 = "other1": {
134169 = "potentially-called-by": [