]> gitweb.factorcode.org Git - factor.git/blob - basis/compiler/tree/cleanup/cleanup.factor
44a6a11802d28ecf6cc464f301c32d6ee90a4b4d
[factor.git] / basis / compiler / tree / cleanup / cleanup.factor
1 ! Copyright (C) 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: kernel accessors sequences sequences.deep combinators fry
4 classes.algebra namespaces assocs words math math.private
5 math.partial-dispatch math.intervals classes classes.tuple
6 classes.tuple.private layouts definitions stack-checker.state
7 stack-checker.branches
8 compiler.intrinsics
9 compiler.tree
10 compiler.tree.combinators
11 compiler.tree.propagation.info
12 compiler.tree.propagation.branches ;
13 IN: compiler.tree.cleanup
14
15 ! A phase run after propagation to finish the job, so to speak.
16 ! Codifies speculative inlining decisions, deletes branches
17 ! marked as never taken, and flattens local recursive blocks
18 ! that do not call themselves.
19
20 GENERIC: delete-node ( node -- )
21
22 M: #call-recursive delete-node
23     dup label>> [ [ eq? not ] with filter ] change-calls drop ;
24
25 M: #return-recursive delete-node
26     label>> f >>return drop ;
27
28 M: node delete-node drop ;
29
30 : delete-nodes ( nodes -- ) [ delete-node ] each-node ;
31
32 GENERIC: cleanup* ( node -- node/nodes )
33
34 : cleanup ( nodes -- nodes' )
35     #! We don't recurse into children here, instead the methods
36     #! do it since the logic is a bit more involved
37     [ cleanup* ] map flatten ;
38
39 : cleanup-folding? ( #call -- ? )
40     node-output-infos
41     [ f ] [ [ literal?>> ] all? ] if-empty ;
42
43 : cleanup-folding ( #call -- nodes )
44     #! Replace a #call having a known result with a #drop of its
45     #! inputs followed by #push nodes for the outputs.
46     [ word>> inlined-dependency depends-on ]
47     [
48         [ node-output-infos ] [ out-d>> ] bi
49         [ [ literal>> ] dip #push ] 2map
50     ]
51     [ in-d>> #drop ]
52     tri prefix ;
53
54 : add-method-dependency ( #call -- )
55     dup method>> word? [
56         [ word>> ] [ class>> ] bi depends-on-generic
57     ] [ drop ] if ;
58
59 : cleanup-inlining ( #call -- nodes )
60     [
61         dup method>>
62         [ add-method-dependency ]
63         [ word>> inlined-dependency depends-on ] if
64     ] [ body>> cleanup ] bi ;
65
66 ! Removing overflow checks
67 : no-overflow-variant ( op -- fast-op )
68     H{
69         { fixnum+ fixnum+fast }
70         { fixnum- fixnum-fast }
71         { fixnum* fixnum*fast }
72         { fixnum-shift fixnum-shift-fast }
73     } at ;
74
75 : (remove-overflow-check?) ( #call -- ? )
76     node-output-infos first class>> fixnum class<= ;
77
78 : small-shift? ( #call -- ? )
79     node-input-infos second interval>>
80     cell-bits tag-bits get - [ neg ] keep [a,b] interval-subset? ;
81
82 : remove-overflow-check? ( #call -- ? )
83     {
84         { [ dup word>> \ fixnum-shift eq? ] [ [ (remove-overflow-check?) ] [ small-shift? ] bi and ] }
85         { [ dup word>> no-overflow-variant ] [ (remove-overflow-check?) ] }
86         [ drop f ]
87     } cond ;
88
89 : remove-overflow-check ( #call -- #call )
90     [ in-d>> ] [ out-d>> ] [ word>> no-overflow-variant ] tri #call cleanup* ;
91
92 M: #call cleanup*
93     {
94         { [ dup body>> ] [ cleanup-inlining ] }
95         { [ dup cleanup-folding? ] [ cleanup-folding ] }
96         { [ dup remove-overflow-check? ] [ remove-overflow-check ] }
97         [ ]
98     } cond ;
99
100 M: #declare cleanup* drop f ;
101
102 : delete-unreachable-branches ( #branch -- )
103     dup live-branches>> '[
104         ,
105         [ [ [ drop ] [ delete-nodes ] if ] 2each ]
106         [ select-children ]
107         2bi
108     ] change-children drop ;
109
110 : fold-only-branch ( #branch -- node/nodes )
111     #! If only one branch is live we don't need to branch at
112     #! all; just drop the condition value.
113     dup live-children sift dup length {
114         { 0 [ 2drop f ] }
115         { 1 [ first swap in-d>> #drop prefix ] }
116         [ 2drop ]
117     } case ;
118
119 SYMBOL: live-branches
120
121 : cleanup-children ( #branch -- )
122     [ [ cleanup ] map ] change-children drop ;
123
124 M: #branch cleanup*
125     {
126         [ delete-unreachable-branches ]
127         [ cleanup-children ]
128         [ fold-only-branch ]
129         [ live-branches>> live-branches set ]
130     } cleave ;
131
132 : output-fs ( values -- nodes )
133     [ f swap #push ] map ;
134
135 : eliminate-single-phi ( #phi -- node )
136     [ phi-in-d>> first ] [ out-d>> ] bi over [ +bottom+ eq? ] all?
137     [ [ drop ] [ output-fs ] bi* ]
138     [ #copy ]
139     if ;
140
141 : eliminate-phi ( #phi -- node )
142     live-branches get sift length {
143         { 0 [ out-d>> output-fs ] }
144         { 1 [ eliminate-single-phi ] }
145         [ drop ]
146     } case ;
147
148 M: #phi cleanup*
149     #! Remove #phi function inputs which no longer exist.
150     live-branches get
151     [ '[ , sift-children ] change-phi-in-d ]
152     [ '[ , sift-children ] change-phi-info-d ]
153     [ '[ , sift-children ] change-terminated ] tri
154     eliminate-phi
155     live-branches off ;
156
157 : >copy ( node -- #copy ) [ in-d>> ] [ out-d>> ] bi #copy ;
158
159 : flatten-recursive ( #recursive -- nodes )
160     #! convert #enter-recursive and #return-recursive into
161     #! #copy nodes.
162     child>>
163     unclip >copy prefix
164     unclip-last >copy suffix ;
165
166 M: #recursive cleanup*
167     #! Inline bodies of #recursive blocks with no calls left.
168     [ cleanup ] change-child
169     dup label>> calls>> empty? [ flatten-recursive ] when ;
170
171 M: node cleanup* ;