OLD | NEW |
---|---|
(Empty) | |
1 import '../compiler.dart'; | |
Siggi Cherem (dart-lang)
2016/09/01 23:51:22
+ copyright
Harry Terkelsen
2016/09/02 17:52:28
Done.
| |
2 import '../io/source_information.dart'; | |
3 import '../js_backend/js_backend.dart'; | |
4 import '../tree/tree.dart' as ast; | |
5 | |
6 import 'graph_builder.dart'; | |
7 import 'locals_handler.dart'; | |
8 import 'nodes.dart'; | |
9 | |
10 class SsaBranch { | |
11 final SsaBranchBuilder branchBuilder; | |
12 final HBasicBlock block; | |
13 LocalsHandler startLocals; | |
14 LocalsHandler exitLocals; | |
15 SubGraph graph; | |
16 | |
17 SsaBranch(this.branchBuilder) : block = new HBasicBlock(); | |
18 } | |
19 | |
20 class SsaBranchBuilder { | |
21 final GraphBuilder builder; | |
22 final Compiler compiler; | |
23 final ast.Node diagnosticNode; | |
24 | |
25 SsaBranchBuilder(this.builder, this.compiler, [this.diagnosticNode]); | |
26 | |
27 void checkNotAborted() { | |
28 if (builder.isAborted()) { | |
29 compiler.unimplemented(diagnosticNode, "aborted control flow"); | |
30 } | |
31 } | |
32 | |
33 void buildCondition( | |
34 void visitCondition(), | |
35 SsaBranch conditionBranch, | |
36 SsaBranch thenBranch, | |
37 SsaBranch elseBranch, | |
38 SourceInformation sourceInformation) { | |
39 startBranch(conditionBranch); | |
40 visitCondition(); | |
41 checkNotAborted(); | |
42 assert(identical(builder.current, builder.lastOpenedBlock)); | |
43 HInstruction conditionValue = builder.popBoolified(); | |
44 HIf branch = new HIf(conditionValue)..sourceInformation = sourceInformation; | |
45 HBasicBlock conditionExitBlock = builder.current; | |
46 builder.close(branch); | |
47 conditionBranch.exitLocals = builder.localsHandler; | |
48 conditionExitBlock.addSuccessor(thenBranch.block); | |
49 conditionExitBlock.addSuccessor(elseBranch.block); | |
50 bool conditionBranchLocalsCanBeReused = | |
51 mergeLocals(conditionBranch, thenBranch, mayReuseFromLocals: true); | |
52 mergeLocals(conditionBranch, elseBranch, | |
53 mayReuseFromLocals: conditionBranchLocalsCanBeReused); | |
54 | |
55 conditionBranch.graph = | |
56 new SubExpression(conditionBranch.block, conditionExitBlock); | |
57 } | |
58 | |
59 /** | |
60 * Returns true if the locals of the [fromBranch] may be reused. A [:true:] | |
61 * return value implies that [mayReuseFromLocals] was set to [:true:]. | |
62 */ | |
63 bool mergeLocals(SsaBranch fromBranch, SsaBranch toBranch, | |
64 {bool mayReuseFromLocals}) { | |
65 LocalsHandler fromLocals = fromBranch.exitLocals; | |
66 if (toBranch.startLocals == null) { | |
67 if (mayReuseFromLocals) { | |
68 toBranch.startLocals = fromLocals; | |
69 return false; | |
70 } else { | |
71 toBranch.startLocals = new LocalsHandler.from(fromLocals); | |
72 return true; | |
73 } | |
74 } else { | |
75 toBranch.startLocals.mergeWith(fromLocals, toBranch.block); | |
76 return true; | |
77 } | |
78 } | |
79 | |
80 void startBranch(SsaBranch branch) { | |
81 builder.graph.addBlock(branch.block); | |
82 builder.localsHandler = branch.startLocals; | |
83 builder.open(branch.block); | |
84 } | |
85 | |
86 HInstruction buildBranch(SsaBranch branch, void visitBranch(), | |
87 SsaBranch joinBranch, bool isExpression) { | |
88 startBranch(branch); | |
89 visitBranch(); | |
90 branch.graph = new SubGraph(branch.block, builder.lastOpenedBlock); | |
91 branch.exitLocals = builder.localsHandler; | |
92 if (!builder.isAborted()) { | |
93 builder.goto(builder.current, joinBranch.block); | |
94 mergeLocals(branch, joinBranch, mayReuseFromLocals: true); | |
95 } | |
96 if (isExpression) { | |
97 checkNotAborted(); | |
98 return builder.pop(); | |
99 } | |
100 return null; | |
101 } | |
102 | |
103 handleIf(void visitCondition(), void visitThen(), void visitElse(), | |
104 {SourceInformation sourceInformation}) { | |
105 if (visitElse == null) { | |
106 // Make sure to have an else part to avoid a critical edge. A | |
107 // critical edge is an edge that connects a block with multiple | |
108 // successors to a block with multiple predecessors. We avoid | |
109 // such edges because they prevent inserting copies during code | |
110 // generation of phi instructions. | |
111 visitElse = () {}; | |
112 } | |
113 | |
114 _handleDiamondBranch(visitCondition, visitThen, visitElse, | |
115 isExpression: false, sourceInformation: sourceInformation); | |
116 } | |
117 | |
118 handleConditional(void visitCondition(), void visitThen(), void visitElse()) { | |
119 assert(visitElse != null); | |
120 _handleDiamondBranch(visitCondition, visitThen, visitElse, | |
121 isExpression: true); | |
122 } | |
123 | |
124 handleIfNull(void left(), void right()) { | |
125 // x ?? y is transformed into: x == null ? y : x | |
126 HInstruction leftExpression; | |
127 handleConditional(() { | |
128 left(); | |
129 leftExpression = builder.pop(); | |
130 builder.pushCheckNull(leftExpression); | |
131 }, right, () => builder.stack.add(leftExpression)); | |
132 } | |
133 | |
134 void handleLogicalAndOr(void left(), void right(), {bool isAnd}) { | |
Siggi Cherem (dart-lang)
2016/09/01 23:51:22
consider making this private and exposing 2 public
Harry Terkelsen
2016/09/02 17:52:27
Seems good, but if I do this then I will have to c
Siggi Cherem (dart-lang)
2016/09/02 17:56:37
Good point - now that we refactored the other, it
| |
135 // x && y is transformed into: | |
136 // t0 = boolify(x); | |
137 // if (t0) { | |
138 // t1 = boolify(y); | |
139 // } | |
140 // result = phi(t1, false); | |
141 // | |
142 // x || y is transformed into: | |
143 // t0 = boolify(x); | |
144 // if (not(t0)) { | |
145 // t1 = boolify(y); | |
146 // } | |
147 // result = phi(t1, true); | |
148 HInstruction boolifiedLeft; | |
149 HInstruction boolifiedRight; | |
150 | |
151 void visitCondition() { | |
152 left(); | |
153 boolifiedLeft = builder.popBoolified(); | |
154 builder.stack.add(boolifiedLeft); | |
155 if (!isAnd) { | |
156 JavaScriptBackend backend = compiler.backend; | |
157 builder.push(new HNot(builder.pop(), backend.boolType)); | |
158 } | |
159 } | |
160 | |
161 void visitThen() { | |
162 right(); | |
163 boolifiedRight = builder.popBoolified(); | |
164 } | |
165 | |
166 handleIf(visitCondition, visitThen, null); | |
167 HConstant notIsAnd = builder.graph.addConstantBool(!isAnd, compiler); | |
168 JavaScriptBackend backend = compiler.backend; | |
169 HPhi result = new HPhi.manyInputs( | |
170 null, <HInstruction>[boolifiedRight, notIsAnd], backend.dynamicType); | |
171 builder.current.addPhi(result); | |
172 builder.stack.add(result); | |
173 } | |
174 | |
175 void _handleDiamondBranch( | |
176 void visitCondition(), void visitThen(), void visitElse(), | |
177 {bool isExpression, SourceInformation sourceInformation}) { | |
178 SsaBranch conditionBranch = new SsaBranch(this); | |
179 SsaBranch thenBranch = new SsaBranch(this); | |
180 SsaBranch elseBranch = new SsaBranch(this); | |
181 SsaBranch joinBranch = new SsaBranch(this); | |
182 | |
183 conditionBranch.startLocals = builder.localsHandler; | |
184 builder.goto(builder.current, conditionBranch.block); | |
185 | |
186 buildCondition(visitCondition, conditionBranch, thenBranch, elseBranch, | |
187 sourceInformation); | |
188 HInstruction thenValue = | |
189 buildBranch(thenBranch, visitThen, joinBranch, isExpression); | |
190 HInstruction elseValue = | |
191 buildBranch(elseBranch, visitElse, joinBranch, isExpression); | |
192 | |
193 if (isExpression) { | |
194 assert(thenValue != null && elseValue != null); | |
195 JavaScriptBackend backend = compiler.backend; | |
196 HPhi phi = new HPhi.manyInputs( | |
197 null, <HInstruction>[thenValue, elseValue], backend.dynamicType); | |
198 joinBranch.block.addPhi(phi); | |
199 builder.stack.add(phi); | |
200 } | |
201 | |
202 HBasicBlock joinBlock; | |
203 // If at least one branch did not abort, open the joinBranch. | |
204 if (!joinBranch.block.predecessors.isEmpty) { | |
205 startBranch(joinBranch); | |
206 joinBlock = joinBranch.block; | |
207 } | |
208 | |
209 HIfBlockInformation info = new HIfBlockInformation( | |
210 new HSubExpressionBlockInformation(conditionBranch.graph), | |
211 new HSubGraphBlockInformation(thenBranch.graph), | |
212 new HSubGraphBlockInformation(elseBranch.graph)); | |
213 | |
214 HBasicBlock conditionStartBlock = conditionBranch.block; | |
215 conditionStartBlock.setBlockFlow(info, joinBlock); | |
216 SubGraph conditionGraph = conditionBranch.graph; | |
217 HIf branch = conditionGraph.end.last; | |
218 assert(branch is HIf); | |
219 branch.blockInformation = conditionStartBlock.blockFlow; | |
220 } | |
221 } | |
OLD | NEW |