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

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 {
105 writes.add(use.field);
106 }
107 }
108
109 // Find the initial values of the fields. A CreateBox has no initial
110 // values. CreateInstance has initial values in the order of the fields.
111 Map<FieldElement, Primitive> fieldInitialValues =
112 <FieldElement, Primitive>{};
113 if (allocation is CreateInstance) {
114 int i = 0;
115 allocation.classElement.forEachInstanceField(
116 (ClassElement enclosingClass, FieldElement field) {
117 Primitive argument = allocation.arguments[i++].definition;
118 fieldInitialValues[field] = argument;
119 });
120 }
121
122 // Create [MutableVariable]s for each written field. Initialize the
123 // MutableVariable with the value from the allocator, or initialize with a
124 // `null` constant if there is not initial value.
125 Map<FieldElement, MutableVariable> cells = <FieldElement, MutableVariable>{} ;
asgerf 2015/08/31 09:57:30 long line :(
sra1 2015/09/02 01:12:57 Done.
126 InteriorNode insertionPoint = allocation.parent; // LetPrim
127 for (FieldElement field in writes) {
128 MutableVariable variable = new MutableVariable(field);
129 cells[field] = variable;
130 Primitive initialValue = fieldInitialValues[field];
131 if (initialValue == null) {
132 assert(allocation is CreateBox);
133 initialValue = new Constant(new NullConstantValue());
134 LetPrim let = new LetPrim(initialValue);
135 let.primitive.parent = let;
136 insertionPoint = insertAtBody(insertionPoint, let);
137 }
138 LetMutable let = new LetMutable(variable, initialValue);
139 let.value.parent = let;
140 insertionPoint = insertAtBody(insertionPoint, let);
141 }
142
143 // Replace references with MutableVariable operations or references to the
144 // field's value.
145 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
146 Node use = ref.parent;
147 if (use is GetField) {
148 GetField getField = use;
149 MutableVariable variable = cells[getField.field];
150 if (variable != null) {
151 GetMutable getter = new GetMutable(variable);
152 getter.variable.parent = getter;
153 getter.substituteFor(getField);
154 getField.parent.primitive = getter; // Replace primitive of LetPrim.
155 deletePrimitive(getField);
156 } else {
157 Primitive value = fieldInitialValues[getField.field];
158 value.substituteFor(getField);
159 deleteLetPrimOf(getField);
160 }
161 } else if (use is SetField && use.object == ref) {
162 SetField setField = use;
163 MutableVariable variable = cells[setField.field];
164 Primitive value = setField.value.definition;
165 SetMutable setter = new SetMutable(variable, value);
166 setter.variable.parent = setter;
167 setter.value.parent = setter;
168 setter.substituteFor(setField);
169 setField.parent.primitive = setter; // Replace primitive of LetPrim.
170 deletePrimitive(setField);
171 } else {
172 throw 'unexpected use: $use';
173 }
174 }
175
176 // Delete [allocation] since that might 'free' another scalar replacement
177 // candidate by deleting the last non-field-access.
178 deleteLetPrimOf(allocation);
179 }
180
181 InteriorNode insertAtBody(InteriorNode insertionPoint, InteriorNode let) {
182 let.parent = insertionPoint;
183 let.body = insertionPoint.body;
184 let.body.parent = let;
185 insertionPoint.body = let;
186 return let;
187 }
188
189 void deleteLetPrimOf(Primitive primitive) {
190 assert(primitive.hasNoUses);
191 LetPrim letPrim = primitive.parent;
192 Node child = letPrim.body;
193 InteriorNode parent = letPrim.parent;
194 child.parent = parent;
195 parent.body = child;
196
197 deletePrimitive(primitive);
198 }
199
200 void deletePrimitive(Primitive primitive) {
201 assert(primitive.hasNoUses);
202 removalVisitor.visit(primitive);
203 }
204
205 void reconsider(Definition node) {
206 if (node is CreateInstance || node is CreateBox) {
207 if (node == _current) return;
208 print('reconsider $node');
asgerf 2015/08/31 09:57:30 Stray print call
sra1 2015/09/02 01:12:57 Done.
209 enqueue(node);
210 }
211 }
212
213 void enqueue(Primitive node) {
214 assert(node is CreateInstance || node is CreateBox);
215 if (_allocations.contains(node)) return;
216 _allocations.add(node);
217 _queue.add(node);
218 }
219
220 // -------------------------- Visitor overrides ------------------------------
221 void visit(Node node) { node.accept(this); }
asgerf 2015/08/31 09:57:30 The visit method is not necessary when extending R
sra1 2015/09/02 01:12:57 Done.
222
223 void visitCreateInstance(CreateInstance node) {
224 enqueue(node);
225 }
226
227 void visitCreateBox(CreateBox node) {
228 enqueue(node);
229 }
230 }
231
232
233 /// Visit a just-deleted subterm and unlink all [Reference]s in it. Reconsider
234 /// allocations for sclara replacement.
asgerf 2015/08/31 09:57:30 sclara -> scalar
sra1 2015/09/02 01:12:57 Done.
235 class ScalarReplacementRemovalVisitor extends RecursiveVisitor {
236 ScalarReplacementVisitor process;
237
238 ScalarReplacementRemovalVisitor(this.process);
239
240 processReference(Reference reference) {
241 process.reconsider(reference.definition);
242 reference.unlink();
243 }
244 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698