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

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

Issue 1573473003: dart2js cps: Do GVN for all primitives except fast constants. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dart2js.cps_ir.gvn; 5 library dart2js.cps_ir.gvn;
6 6
7 import 'cps_ir_nodes.dart'; 7 import 'cps_ir_nodes.dart';
8 import '../universe/side_effects.dart'; 8 import '../universe/side_effects.dart';
9 import '../elements/elements.dart'; 9 import '../elements/elements.dart';
10 import 'optimizers.dart' show Pass; 10 import 'optimizers.dart' show Pass;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 /// Effect numbers at the given join point. 57 /// Effect numbers at the given join point.
58 Map<Continuation, EffectNumbers> effectsAt = <Continuation, EffectNumbers>{}; 58 Map<Continuation, EffectNumbers> effectsAt = <Continuation, EffectNumbers>{};
59 59
60 /// The effect numbers at the current position (during traversal). 60 /// The effect numbers at the current position (during traversal).
61 EffectNumbers effectNumbers = new EffectNumbers(); 61 EffectNumbers effectNumbers = new EffectNumbers();
62 62
63 /// The loop currently enclosing the binding of a given primitive. 63 /// The loop currently enclosing the binding of a given primitive.
64 final Map<Primitive, Continuation> loopHeaderFor = 64 final Map<Primitive, Continuation> loopHeaderFor =
65 <Primitive, Continuation>{}; 65 <Primitive, Continuation>{};
66 66
67 /// The loop to which a given trivial primitive can be hoisted.
68 final Map<Primitive, Continuation> potentialLoopHeaderFor =
69 <Primitive, Continuation>{};
70
71 /// The GVNs for primitives that have been hoisted outside the given loop. 67 /// The GVNs for primitives that have been hoisted outside the given loop.
72 /// 68 ///
73 /// These should be removed from the environment when exiting the loop. 69 /// These should be removed from the environment when exiting the loop.
74 final Map<Continuation, List<int>> loopHoistedBindings = 70 final Map<Continuation, List<int>> loopHoistedBindings =
75 <Continuation, List<int>>{}; 71 <Continuation, List<int>>{};
76 72
77 /// Maps GVNs to a currently-in-scope binding for that value. 73 /// Maps GVNs to a currently-in-scope binding for that value.
78 final Map<int, Primitive> environment = <int, Primitive>{}; 74 final Map<int, Primitive> environment = <int, Primitive>{};
79 75
80 /// Maps GVN'able primitives to their global value number. 76 /// Maps GVN'able primitives to their global value number.
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 } 144 }
149 145
150 // Compute the GVN for this primitive. 146 // Compute the GVN for this primitive.
151 int gvn = gvnTable.insert(vector); 147 int gvn = gvnTable.insert(vector);
152 gvnFor[prim] = gvn; 148 gvnFor[prim] = gvn;
153 149
154 // Try to reuse a previously computed value with the same GVN. 150 // Try to reuse a previously computed value with the same GVN.
155 Primitive existing = environment[gvn]; 151 Primitive existing = environment[gvn];
156 if (existing != null && 152 if (existing != null &&
157 canReplaceWithExistingValue(prim) && 153 canReplaceWithExistingValue(prim) &&
158 !isTrivialPrimitive(prim)) { 154 !isFastConstant(prim)) {
159 if (prim is Interceptor) { 155 if (prim is Interceptor) {
160 Interceptor interceptor = existing; 156 Interceptor interceptor = existing;
161 interceptor.interceptedClasses.addAll(prim.interceptedClasses); 157 interceptor.interceptedClasses.addAll(prim.interceptedClasses);
162 } 158 }
163 prim..replaceUsesWith(existing)..destroy(); 159 prim..replaceUsesWith(existing)..destroy();
164 node.remove(); 160 node.remove();
165 return next; 161 return next;
166 } 162 }
167 163
168 if (tryToHoistOutOfLoop(prim, gvn)) { 164 if (tryToHoistOutOfLoop(prim, gvn)) {
(...skipping 25 matching lines...) Expand all
194 // Find the depth of the outermost scope where we can bind the primitive 190 // Find the depth of the outermost scope where we can bind the primitive
195 // without bringing a reference out of scope. 0 is the depth of the 191 // without bringing a reference out of scope. 0 is the depth of the
196 // top-level scope. 192 // top-level scope.
197 int hoistDepth = 0; 193 int hoistDepth = 0;
198 List<Primitive> inputsHoistedOnDemand = <Primitive>[]; 194 List<Primitive> inputsHoistedOnDemand = <Primitive>[];
199 InputVisitor.forEach(prim, (Reference ref) { 195 InputVisitor.forEach(prim, (Reference ref) {
200 Primitive input = ref.definition; 196 Primitive input = ref.definition;
201 if (canIgnoreRefinementGuards(prim)) { 197 if (canIgnoreRefinementGuards(prim)) {
202 input = input.effectiveDefinition; 198 input = input.effectiveDefinition;
203 } 199 }
204 Continuation loopHeader; 200 if (isFastConstant(input)) {
205 if (potentialLoopHeaderFor.containsKey(input)) { 201 // Fast constants can be hoisted all the way out, but should only be
206 // This is a reference to a value that can be hoisted further out than 202 // hoisted if needed to hoist something else.
207 // it currently is. If we decide to hoist [prim], we must also hoist
208 // such dependent values.
209 loopHeader = potentialLoopHeaderFor[input];
210 inputsHoistedOnDemand.add(input); 203 inputsHoistedOnDemand.add(input);
211 } else { 204 } else {
212 loopHeader = loopHeaderFor[input]; 205 Continuation loopHeader = loopHeaderFor[input];
213 } 206 Continuation referencedLoop =
214 Continuation referencedLoop = 207 loopHierarchy.lowestCommonAncestor(loopHeader, currentLoopHeader);
215 loopHierarchy.lowestCommonAncestor(loopHeader, currentLoopHeader); 208 int depth = loopHierarchy.getDepth(referencedLoop);
216 int depth = loopHierarchy.getDepth(referencedLoop); 209 if (depth > hoistDepth) {
217 if (depth > hoistDepth) { 210 hoistDepth = depth;
218 hoistDepth = depth; 211 }
219 } 212 }
220 }); 213 });
221 214
222 // Bail out if it can not be hoisted further out than it is now. 215 // Bail out if it can not be hoisted further out than it is now.
223 if (hoistDepth == loopHierarchy.getDepth(currentLoopHeader)) return false; 216 if (hoistDepth == loopHierarchy.getDepth(currentLoopHeader)) return false;
224 217
225 // Walk up the loop hierarchy and check at every step that any heap 218 // Walk up the loop hierarchy and check at every step that any heap
226 // dependencies can safely be hoisted out of the loop. 219 // dependencies can safely be hoisted out of the loop.
227 Continuation enclosingLoop = currentLoopHeader; 220 Continuation enclosingLoop = currentLoopHeader;
228 Continuation hoistTarget = null; 221 Continuation hoistTarget = null;
229 while (loopHierarchy.getDepth(enclosingLoop) > hoistDepth && 222 while (loopHierarchy.getDepth(enclosingLoop) > hoistDepth &&
230 canHoistHeapDependencyOutOfLoop(prim, enclosingLoop)) { 223 canHoistHeapDependencyOutOfLoop(prim, enclosingLoop)) {
231 hoistTarget = enclosingLoop; 224 hoistTarget = enclosingLoop;
232 enclosingLoop = loopHierarchy.getEnclosingLoop(enclosingLoop); 225 enclosingLoop = loopHierarchy.getEnclosingLoop(enclosingLoop);
233 } 226 }
234 227
235 // Bail out if heap dependencies prohibit any hoisting at all. 228 // Bail out if heap dependencies prohibit any hoisting at all.
236 if (hoistTarget == null) return false; 229 if (hoistTarget == null) return false;
237 230
238 if (isTrivialPrimitive(prim)) { 231 if (isFastConstant(prim)) {
239 // The overhead from introducting a temporary might be greater than 232 // The overhead from introducting a temporary might be greater than
240 // the overhead of evaluating this primitive at every iteration. 233 // the overhead of evaluating this primitive at every iteration.
241 // Only hoist if this enables hoisting of a non-trivial primitive. 234 // Only hoist if this enables hoisting of a non-trivial primitive.
242 potentialLoopHeaderFor[prim] = enclosingLoop;
243 return true; 235 return true;
244 } 236 }
245 237
246 LetCont loopBinding = hoistTarget.parent; 238 LetCont loopBinding = hoistTarget.parent;
247 239
248 // The primitive may depend on values that have not yet been 240 // The primitive may depend on values that have not yet been
249 // hoisted as far as they can. Hoist those now. 241 // hoisted as far as they can. Hoist those now.
250 for (Primitive input in inputsHoistedOnDemand) { 242 for (Primitive input in inputsHoistedOnDemand) {
251 hoistTrivialPrimitive(input, loopBinding, enclosingLoop); 243 hoistTrivialPrimitive(input, loopBinding, enclosingLoop);
252 } 244 }
(...skipping 26 matching lines...) Expand all
279 .putIfAbsent(hoistTarget, () => <int>[]) 271 .putIfAbsent(hoistTarget, () => <int>[])
280 .add(gvn); 272 .add(gvn);
281 return true; 273 return true;
282 } 274 }
283 275
284 /// If the given primitive is a trivial primitive that should be hoisted 276 /// If the given primitive is a trivial primitive that should be hoisted
285 /// on-demand, hoist it and its dependent values above [loopBinding]. 277 /// on-demand, hoist it and its dependent values above [loopBinding].
286 void hoistTrivialPrimitive(Primitive prim, 278 void hoistTrivialPrimitive(Primitive prim,
287 LetCont loopBinding, 279 LetCont loopBinding,
288 Continuation enclosingLoop) { 280 Continuation enclosingLoop) {
289 if (!potentialLoopHeaderFor.containsKey(prim)) return; 281 assert(isFastConstant(prim));
290 assert(isTrivialPrimitive(prim));
291 282
292 // The primitive might already be bound in an outer scope. Do not relocate 283 // The primitive might already be bound in an outer scope. Do not relocate
293 // the primitive unless we are lifting it. For example; 284 // the primitive unless we are lifting it. For example;
294 // t1 = a + b 285 // t1 = a + b
295 // t2 = t1 + c 286 // t2 = t1 + c
296 // t3 = t1 * t2 287 // t3 = t1 * t2
297 // If it was decided that `t3` should be hoisted, `t1` will be seen twice by 288 // If it was decided that `t3` should be hoisted, `t1` will be seen twice by
298 // this method: by the direct reference and by reference through `t2`. 289 // this method: by the direct reference and by reference through `t2`.
299 // The second time it is seen, it will already have been moved. 290 // The second time it is seen, it will already have been moved.
300 Continuation currentLoop = loopHeaderFor[prim]; 291 Continuation currentLoop = loopHeaderFor[prim];
301 int currentDepth = loopHierarchy.getDepth(currentLoop); 292 int currentDepth = loopHierarchy.getDepth(currentLoop);
302 int targetDepth = loopHierarchy.getDepth(enclosingLoop); 293 int targetDepth = loopHierarchy.getDepth(enclosingLoop);
303 if (currentDepth <= targetDepth) return; 294 if (currentDepth <= targetDepth) return;
304 295
305 // Hoist the trivial primitives being depended on so they remain in scope. 296 // Hoist the trivial primitives being depended on so they remain in scope.
306 InputVisitor.forEach(prim, (Reference ref) { 297 InputVisitor.forEach(prim, (Reference ref) {
307 hoistTrivialPrimitive(ref.definition, loopBinding, enclosingLoop); 298 hoistTrivialPrimitive(ref.definition, loopBinding, enclosingLoop);
308 }); 299 });
309 300
310 // Move the primitive. 301 // Move the primitive.
311 LetPrim binding = prim.parent; 302 LetPrim binding = prim.parent;
312 binding.remove(); 303 binding.remove();
313 binding.insertAbove(loopBinding); 304 binding.insertAbove(loopBinding);
314 loopHeaderFor[prim] = enclosingLoop; 305 loopHeaderFor[prim] = enclosingLoop;
315
316 if (potentialLoopHeaderFor[prim] == enclosingLoop) {
317 potentialLoopHeaderFor.remove(prim);
318 }
319 } 306 }
320 307
321 bool canIgnoreRefinementGuards(Primitive primitive) { 308 bool canIgnoreRefinementGuards(Primitive primitive) {
322 return primitive is Interceptor; 309 return primitive is Interceptor;
323 } 310 }
324 311
325 /// Returns true if the given primitive is so cheap at runtime that it is 312 /// Returns true if [prim] is a constant that has no significant runtime cost.
326 /// better to (redundantly) recompute it rather than introduce a temporary. 313 bool isFastConstant(Primitive prim) {
327 bool isTrivialPrimitive(Primitive primitive) { 314 return prim is Constant && (prim.value.isPrimitive || prim.value.isDummy);
328 return primitive is ApplyBuiltinOperator ||
329 primitive is Constant && isTrivialConstant(primitive.value);
330 }
331
332 /// Returns true if the given constant has almost no runtime cost.
333 bool isTrivialConstant(ConstantValue value) {
334 return value.isPrimitive || value.isDummy;
335 } 315 }
336 316
337 /// True if [element] is a final or constant field or a function. 317 /// True if [element] is a final or constant field or a function.
338 bool isImmutable(Element element) { 318 bool isImmutable(Element element) {
339 if (element.isField && backend.isNative(element)) return false; 319 if (element.isField && backend.isNative(element)) return false;
340 return element.isField && world.fieldNeverChanges(element) || 320 return element.isField && world.fieldNeverChanges(element) ||
341 element.isFunction; 321 element.isFunction;
342 } 322 }
343 323
344 bool isImmutableLength(GetLength length) { 324 bool isImmutableLength(GetLength length) {
(...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after
742 722
743 @override 723 @override
744 processReference(Reference ref) { 724 processReference(Reference ref) {
745 callback(ref); 725 callback(ref);
746 } 726 }
747 727
748 static void forEach(Primitive node, ReferenceCallback callback) { 728 static void forEach(Primitive node, ReferenceCallback callback) {
749 new InputVisitor(callback).visit(node); 729 new InputVisitor(callback).visit(node);
750 } 730 }
751 } 731 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698