Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1398)

Side by Side Diff: pkg/compiler/lib/src/cps_ir/scalar_replacement.dart

Issue 1319303002: dart2js cps: Scalar replacement of aggregates (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 import 'optimizers.dart';
6
7 import 'dart:collection' show Queue;
8
9 import '../closure.dart' show
10 ClosureClassElement, Identifiers;
11 import '../common/names.dart' show
12 Selectors, Identifiers;
13 import '../compiler.dart' as dart2js show
14 Compiler;
15 import '../constants/constant_system.dart';
16 import '../constants/values.dart';
17 import '../dart_types.dart' as types;
18 import '../diagnostics/invariant.dart' as dart2js show
19 InternalErrorFunction;
20 import '../elements/elements.dart';
21 import '../io/source_information.dart' show SourceInformation;
22 import '../resolution/access_semantics.dart';
23 import '../resolution/operators.dart';
24 import '../resolution/send_structure.dart';
25 import '../tree/tree.dart' as ast;
26 import '../types/types.dart';
27 import '../types/constants.dart' show computeTypeMask;
28 import '../universe/universe.dart';
29 import '../world.dart' show World;
30 import 'cps_fragment.dart';
31 import 'cps_ir_nodes.dart';
32 import 'cps_ir_nodes_sexpr.dart' show SExpressionStringifier;
33
34 /**
35 * Replaces aggregates with a set of local values. Performs inlining of
36 * single-use closures to generate more replacable aggregates.
37 */
38 class ScalarReplacer extends Pass {
39 String get passName => 'Scalar replacement';
40
41 final dart2js.InternalErrorFunction _internalError;
42
43 ScalarReplacer(dart2js.Compiler compiler)
44 : _internalError = compiler.internalError;
45
46 @override
47 void rewrite(FunctionDefinition root) {
48 // Set all parent pointers.
49 new ParentVisitor().visit(root);
50 ScalarReplacementVisitor analyzer =
51 new ScalarReplacementVisitor(_internalError);
52 analyzer.analyze(root);
53 analyzer.process();
54 }
55 }
56
57 /**
58 * Do scalar replacement of aggregates on instances. Since scalar replacement
59 * can create new candidiates, iterate until all scalar replacements are done.
60 */
61 class ScalarReplacementVisitor extends RecursiveVisitor {
62
63 final dart2js.InternalErrorFunction internalError;
64 ScalarReplacementRemovalVisitor removalVisitor;
65
66 Primitive _current = null;
67 Set<Primitive> _allocations = new Set<Primitive>();
68 Queue<Primitive> _queue = new Queue<Primitive>();
69
70 ScalarReplacementVisitor(this.internalError) {
71 removalVisitor = new ScalarReplacementRemovalVisitor(this);
72 }
73
74 void analyze(FunctionDefinition root) {
75 visit(root);
76 }
77
78 void process() {
79 while (_queue.isNotEmpty) {
80 Primitive allocation = _queue.removeFirst();
81 _allocations.remove(allocation);
82 _current = allocation;
83 tryScalarReplacement(allocation);
84 }
85 }
86
87 void tryScalarReplacement(Primitive allocation) {
88
89 // We can do scalar replacement of an aggregate if all uses of an allocation
90 // are reads or writes.
91 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
92 Node use = ref.parent;
93 if (use is GetField) continue;
94 if (use is SetField && use.object == ref) continue;
95 return;
96 }
97
98 Set<FieldElement> reads = new Set<FieldElement>();
99 Set<FieldElement> writes = new Set<FieldElement>();
100 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
101 Node use = ref.parent;
102 if (use is GetField) {
103 reads.add(use.field);
104 } else if (use is SetField) {
105 writes.add(use.field);
106 } else {
107 assert(false);
108 }
109 }
110
111 // Find the initial values of the fields. A CreateBox has no initial
112 // values. CreateInstance has initial values in the order of the fields.
113 Map<FieldElement, Primitive> fieldInitialValues =
114 <FieldElement, Primitive>{};
115 if (allocation is CreateInstance) {
116 int i = 0;
117 allocation.classElement.forEachInstanceField(
118 (ClassElement enclosingClass, FieldElement field) {
119 Primitive argument = allocation.arguments[i++].definition;
120 fieldInitialValues[field] = argument;
121 });
122 }
123
124 // Create [MutableVariable]s for each written field. Initialize the
125 // MutableVariable with the value from the allocator, or initialize with a
126 // `null` constant if there is not initial value.
127 Map<FieldElement, MutableVariable> cells =
128 <FieldElement, MutableVariable>{};
129 InteriorNode insertionPoint = allocation.parent; // LetPrim
130 for (FieldElement field in writes) {
131 MutableVariable variable = new MutableVariable(field);
132 cells[field] = variable;
133 Primitive initialValue = fieldInitialValues[field];
134 if (initialValue == null) {
135 assert(allocation is CreateBox);
136 initialValue = new Constant(new NullConstantValue());
137 LetPrim let = new LetPrim(initialValue);
138 let.primitive.parent = let;
139 insertionPoint = insertAtBody(insertionPoint, let);
140 }
141 LetMutable let = new LetMutable(variable, initialValue);
142 let.value.parent = let;
143 insertionPoint = insertAtBody(insertionPoint, let);
144 }
145
146 // Replace references with MutableVariable operations or references to the
147 // field's value.
148 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
149 Node use = ref.parent;
150 if (use is GetField) {
151 GetField getField = use;
152 MutableVariable variable = cells[getField.field];
153 if (variable != null) {
154 GetMutable getter = new GetMutable(variable);
155 getter.variable.parent = getter;
156 getter.substituteFor(getField);
157 replacePrimitive(getField, getter);
158 deletePrimitive(getField);
159 } else {
160 Primitive value = fieldInitialValues[getField.field];
161 value.substituteFor(getField);
162 deleteLetPrimOf(getField);
163 }
164 } else if (use is SetField && use.object == ref) {
165 SetField setField = use;
166 MutableVariable variable = cells[setField.field];
167 Primitive value = setField.value.definition;
168 SetMutable setter = new SetMutable(variable, value);
169 setter.variable.parent = setter;
170 setter.value.parent = setter;
171 setter.substituteFor(setField);
172 replacePrimitive(setField, setter);
173 deletePrimitive(setField);
174 } else {
175 assert(false);
176 }
177 }
178
179 // Delete [allocation] since that might 'free' another scalar replacement
180 // candidate by deleting the last non-field-access.
181 deleteLetPrimOf(allocation);
182 }
183
184 InteriorNode insertAtBody(
185 InteriorNode insertionPoint, InteriorExpression let) {
186 let.parent = insertionPoint;
187 let.body = insertionPoint.body;
188 let.body.parent = let;
189 insertionPoint.body = let;
190 return let;
191 }
192
193 /// Replaces [old] with [primitive] in [old]'s parent [LetPrim].
194 void replacePrimitive(Primitive old, Primitive primitive) {
195 LetPrim letPrim = old.parent;
196 letPrim.primitive = primitive;
197 }
198
199 void deleteLetPrimOf(Primitive primitive) {
200 assert(primitive.hasNoUses);
201 LetPrim letPrim = primitive.parent;
202 Node child = letPrim.body;
203 InteriorNode parent = letPrim.parent;
204 child.parent = parent;
205 parent.body = child;
206
207 deletePrimitive(primitive);
208 }
209
210 void deletePrimitive(Primitive primitive) {
211 assert(primitive.hasNoUses);
212 removalVisitor.visit(primitive);
213 }
214
215 void reconsider(Definition node) {
216 if (node is CreateInstance || node is CreateBox) {
217 if (node == _current) return;
218 enqueue(node);
219 }
220 }
221
222 void enqueue(Primitive node) {
223 assert(node is CreateInstance || node is CreateBox);
224 if (_allocations.contains(node)) return;
225 _allocations.add(node);
226 _queue.add(node);
227 }
228
229 // -------------------------- Visitor overrides ------------------------------
230 void visitCreateInstance(CreateInstance node) {
231 enqueue(node);
232 }
233
234 void visitCreateBox(CreateBox node) {
235 enqueue(node);
236 }
237 }
238
239
240 /// Visit a just-deleted subterm and unlink all [Reference]s in it. Reconsider
241 /// allocations for scalar replacement.
242 class ScalarReplacementRemovalVisitor extends RecursiveVisitor {
243 ScalarReplacementVisitor process;
244
245 ScalarReplacementRemovalVisitor(this.process);
246
247 processReference(Reference reference) {
248 process.reconsider(reference.definition);
249 reference.unlink();
250 }
251 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/optimizers.dart ('k') | pkg/compiler/lib/src/js_backend/codegen/task.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698