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

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

Issue 1518003002: dart2js cps: Better GVN for fixed lengths and unmodified fields. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Merge Created 5 years 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 | pkg/compiler/lib/src/js_backend/codegen/task.dart » ('j') | 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;
11 import 'loop_hierarchy.dart'; 11 import 'loop_hierarchy.dart';
12 import 'loop_effects.dart'; 12 import 'loop_effects.dart';
13 import '../world.dart'; 13 import '../world.dart';
14 import '../compiler.dart' show Compiler; 14 import '../compiler.dart' show Compiler;
15 import '../js_backend/js_backend.dart' show JavaScriptBackend; 15 import '../js_backend/js_backend.dart' show JavaScriptBackend;
16 import '../constants/values.dart'; 16 import '../constants/values.dart';
17 import 'type_mask_system.dart';
17 18
18 /// Eliminates redundant primitives by reusing the value of another primitive 19 /// Eliminates redundant primitives by reusing the value of another primitive
19 /// that is known to have the same result. Primitives are also hoisted out of 20 /// that is known to have the same result. Primitives are also hoisted out of
20 /// loops when possible. 21 /// loops when possible.
21 /// 22 ///
22 /// Reusing values can introduce new temporaries, which in some cases is more 23 /// Reusing values can introduce new temporaries, which in some cases is more
23 /// expensive than recomputing the value on-demand. For example, pulling an 24 /// expensive than recomputing the value on-demand. For example, pulling an
24 /// expression such as "n+1" out of a loop is generally not worth it. 25 /// expression such as "n+1" out of a loop is generally not worth it.
25 /// Such primitives are said to be "trivial". 26 /// Such primitives are said to be "trivial".
26 /// 27 ///
(...skipping 10 matching lines...) Expand all
37 // 38 //
38 // TODO(asgerf): Put this pass at a better place in the pipeline. We currently 39 // TODO(asgerf): Put this pass at a better place in the pipeline. We currently
39 // cannot put it anywhere we want, because this pass relies on refinement 40 // cannot put it anywhere we want, because this pass relies on refinement
40 // nodes being present (for safety), whereas other passes rely on refinement 41 // nodes being present (for safety), whereas other passes rely on refinement
41 // nodes being absent (for simplicity & precision). 42 // nodes being absent (for simplicity & precision).
42 // 43 //
43 class GVN extends TrampolineRecursiveVisitor implements Pass { 44 class GVN extends TrampolineRecursiveVisitor implements Pass {
44 String get passName => 'GVN'; 45 String get passName => 'GVN';
45 46
46 final Compiler compiler; 47 final Compiler compiler;
48 final TypeMaskSystem types;
47 JavaScriptBackend get backend => compiler.backend; 49 JavaScriptBackend get backend => compiler.backend;
48 World get world => compiler.world; 50 World get world => compiler.world;
49 51
50 final GvnTable gvnTable = new GvnTable(); 52 final GvnTable gvnTable = new GvnTable();
51 GvnVectorBuilder gvnVectorBuilder; 53 GvnVectorBuilder gvnVectorBuilder;
52 LoopHierarchy loopHierarchy; 54 LoopHierarchy loopHierarchy;
53 LoopSideEffects loopEffects; 55 LoopSideEffects loopEffects;
54 56
55 /// Effect numbers at the given join point. 57 /// Effect numbers at the given join point.
56 Map<Continuation, EffectNumbers> effectsAt = <Continuation, EffectNumbers>{}; 58 Map<Continuation, EffectNumbers> effectsAt = <Continuation, EffectNumbers>{};
(...skipping 16 matching lines...) Expand all
73 <Continuation, List<int>>{}; 75 <Continuation, List<int>>{};
74 76
75 /// Maps GVNs to a currently-in-scope binding for that value. 77 /// Maps GVNs to a currently-in-scope binding for that value.
76 final Map<int, Primitive> environment = <int, Primitive>{}; 78 final Map<int, Primitive> environment = <int, Primitive>{};
77 79
78 /// Maps GVN'able primitives to their global value number. 80 /// Maps GVN'able primitives to their global value number.
79 final Map<Primitive, int> gvnFor = <Primitive, int>{}; 81 final Map<Primitive, int> gvnFor = <Primitive, int>{};
80 82
81 Continuation currentLoopHeader; 83 Continuation currentLoopHeader;
82 84
83 GVN(this.compiler); 85 GVN(this.compiler, this.types);
84 86
85 int _usedEffectNumbers = 0; 87 int _usedEffectNumbers = 0;
86 int makeNewEffect() => ++_usedEffectNumbers; 88 int makeNewEffect() => ++_usedEffectNumbers;
87 89
88 void rewrite(FunctionDefinition node) { 90 void rewrite(FunctionDefinition node) {
89 gvnVectorBuilder = new GvnVectorBuilder(gvnFor, backend); 91 gvnVectorBuilder = new GvnVectorBuilder(gvnFor, compiler, types);
90 loopHierarchy = new LoopHierarchy(node); 92 loopHierarchy = new LoopHierarchy(node);
91 loopEffects = 93 loopEffects =
92 new LoopSideEffects(node, world, loopHierarchy: loopHierarchy); 94 new LoopSideEffects(node, world, loopHierarchy: loopHierarchy);
93 visit(node); 95 visit(node);
94 } 96 }
95 97
96 // ------------------ GLOBAL VALUE NUMBERING --------------------- 98 // ------------------ GLOBAL VALUE NUMBERING ---------------------
97 99
98 @override 100 @override
99 Expression traverseLetPrim(LetPrim node) { 101 Expression traverseLetPrim(LetPrim node) {
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 } 308 }
307 309
308 /// Returns true if the given constant has almost no runtime cost. 310 /// Returns true if the given constant has almost no runtime cost.
309 bool isTrivialConstant(ConstantValue value) { 311 bool isTrivialConstant(ConstantValue value) {
310 return value.isPrimitive || value.isDummy; 312 return value.isPrimitive || value.isDummy;
311 } 313 }
312 314
313 /// True if [element] is a final or constant field or a function. 315 /// True if [element] is a final or constant field or a function.
314 bool isImmutable(Element element) { 316 bool isImmutable(Element element) {
315 if (element.isField && backend.isNative(element)) return false; 317 if (element.isField && backend.isNative(element)) return false;
316 return element.isField && (element.isFinal || element.isConst) || 318 return element.isField && world.fieldNeverChanges(element) ||
317 element.isFunction; 319 element.isFunction;
318 } 320 }
319 321
322 bool isImmutableLength(GetLength length) {
323 return types.isDefinitelyFixedLengthIndexable(length.object.definition.type,
324 allowNull: true);
325 }
326
320 /// Assuming [prim] has no side effects, returns true if it can safely 327 /// Assuming [prim] has no side effects, returns true if it can safely
321 /// be hoisted out of [loop] without changing its value. 328 /// be hoisted out of [loop] without changing its value.
322 bool canHoistHeapDependencyOutOfLoop(Primitive prim, Continuation loop) { 329 bool canHoistHeapDependencyOutOfLoop(Primitive prim, Continuation loop) {
323 assert(prim.isSafeForElimination); 330 assert(prim.isSafeForElimination);
324 if (prim is GetLength) { 331 if (prim is GetLength && !isImmutableLength(prim)) {
325 return !loopEffects.loopChangesLength(loop); 332 return !loopEffects.loopChangesLength(loop);
326 } else if (prim is GetField && !isImmutable(prim.field)) { 333 } else if (prim is GetField && !isImmutable(prim.field)) {
327 return !loopEffects.getSideEffectsInLoop(loop).changesInstanceProperty(); 334 return !loopEffects.getSideEffectsInLoop(loop).changesInstanceProperty();
328 } else if (prim is GetStatic && !isImmutable(prim.element)) { 335 } else if (prim is GetStatic && !isImmutable(prim.element)) {
329 return !loopEffects.getSideEffectsInLoop(loop).changesStaticProperty(); 336 return !loopEffects.getSideEffectsInLoop(loop).changesStaticProperty();
330 } else if (prim is GetIndex) { 337 } else if (prim is GetIndex) {
331 return !loopEffects.getSideEffectsInLoop(loop).changesIndex(); 338 return !loopEffects.getSideEffectsInLoop(loop).changesIndex();
332 } else { 339 } else {
333 return true; 340 return true;
334 } 341 }
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
569 /// This includes the instruction type, inputs, effect numbers for any part 576 /// This includes the instruction type, inputs, effect numbers for any part
570 /// of the heap being depended on, as well as any instruction-specific payload 577 /// of the heap being depended on, as well as any instruction-specific payload
571 /// such as any DartTypes, Elements, and operator kinds. 578 /// such as any DartTypes, Elements, and operator kinds.
572 /// 579 ///
573 /// Each `visit` or `process` method for a primitive must initialize [vector] 580 /// Each `visit` or `process` method for a primitive must initialize [vector]
574 /// if the primitive is GVN'able and fill in any components except the inputs. 581 /// if the primitive is GVN'able and fill in any components except the inputs.
575 /// The inputs will be filled in by [processReference]. 582 /// The inputs will be filled in by [processReference].
576 class GvnVectorBuilder extends DeepRecursiveVisitor { 583 class GvnVectorBuilder extends DeepRecursiveVisitor {
577 List vector; 584 List vector;
578 final Map<Primitive, int> gvnFor; 585 final Map<Primitive, int> gvnFor;
579 final JavaScriptBackend backend; 586 final Compiler compiler;
587 World get world => compiler.world;
588 JavaScriptBackend get backend => compiler.backend;
589 final TypeMaskSystem types;
580 EffectNumbers effectNumbers; 590 EffectNumbers effectNumbers;
581 591
582 GvnVectorBuilder(this.gvnFor, this.backend); 592 GvnVectorBuilder(this.gvnFor, this.compiler, this.types);
583 593
584 List make(Primitive prim, EffectNumbers effectNumbers) { 594 List make(Primitive prim, EffectNumbers effectNumbers) {
585 this.effectNumbers = effectNumbers; 595 this.effectNumbers = effectNumbers;
586 vector = null; 596 vector = null;
587 visit(prim); 597 visit(prim);
588 return vector; 598 return vector;
589 } 599 }
590 600
591 /// The `process` methods below do not insert the referenced arguments into 601 /// The `process` methods below do not insert the referenced arguments into
592 /// the vector, but instead rely on them being inserted here. 602 /// the vector, but instead rely on them being inserted here.
593 processReference(Reference ref) { 603 processReference(Reference ref) {
594 if (vector == null) return; 604 if (vector == null) return;
595 Primitive prim = ref.definition.effectiveDefinition; 605 Primitive prim = ref.definition.effectiveDefinition;
596 vector.add(gvnFor[prim] ?? prim); 606 vector.add(gvnFor[prim] ?? prim);
597 } 607 }
598 608
599 processTypeTest(TypeTest node) { 609 processTypeTest(TypeTest node) {
600 vector = [GvnCode.TYPE_TEST, node.dartType]; 610 vector = [GvnCode.TYPE_TEST, node.dartType];
601 } 611 }
602 612
603 processTypeTestViaFlag(TypeTestViaFlag node) { 613 processTypeTestViaFlag(TypeTestViaFlag node) {
604 vector = [GvnCode.TYPE_TEST_VIA_FLAG, node.dartType]; 614 vector = [GvnCode.TYPE_TEST_VIA_FLAG, node.dartType];
605 } 615 }
606 616
607 processApplyBuiltinOperator(ApplyBuiltinOperator node) { 617 processApplyBuiltinOperator(ApplyBuiltinOperator node) {
608 vector = [GvnCode.BUILTIN_OPERATOR, node.operator.index]; 618 vector = [GvnCode.BUILTIN_OPERATOR, node.operator.index];
609 } 619 }
610 620
611 processGetLength(GetLength node) { 621 processGetLength(GetLength node) {
612 // TODO(asgerf): Take fixed lengths into account? 622 if (isImmutableLength(node)) {
613 vector = [GvnCode.GET_LENGTH, effectNumbers.indexableLength]; 623 // Omit the effect number for fixed-length lists. Note that if a the list
624 // gets refined to a fixed-length type, we still won't be able to GVN a
625 // GetLength across the refinement, because the first GetLength uses an
626 // effect number in its vector while the second one does not.
627 vector = [GvnCode.GET_LENGTH];
628 } else {
629 vector = [GvnCode.GET_LENGTH, effectNumbers.indexableLength];
630 }
614 } 631 }
615 632
616 bool isImmutable(Element element) { 633 bool isImmutable(Element element) {
617 return element.isFunction || 634 return element.isFunction ||
618 element.isField && (element.isFinal || element.isConst); 635 element.isField && world.fieldNeverChanges(element);
636 }
637
638 bool isImmutableLength(GetLength length) {
639 return types.isDefinitelyFixedLengthIndexable(length.object.definition.type,
640 allowNull: true);
619 } 641 }
620 642
621 bool isNativeField(FieldElement field) { 643 bool isNativeField(FieldElement field) {
622 // TODO(asgerf): We should add a GetNativeField instruction. 644 // TODO(asgerf): We should add a GetNativeField instruction.
623 return backend.isNative(field); 645 return backend.isNative(field);
624 } 646 }
625 647
626 processGetField(GetField node) { 648 processGetField(GetField node) {
627 if (isNativeField(node.field)) { 649 if (isNativeField(node.field)) {
628 vector = null; // Native field access cannot be GVN'ed. 650 vector = null; // Native field access cannot be GVN'ed.
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
697 719
698 @override 720 @override
699 processReference(Reference ref) { 721 processReference(Reference ref) {
700 callback(ref); 722 callback(ref);
701 } 723 }
702 724
703 static void forEach(Primitive node, ReferenceCallback callback) { 725 static void forEach(Primitive node, ReferenceCallback callback) {
704 new InputVisitor(callback).visit(node); 726 new InputVisitor(callback).visit(node);
705 } 727 }
706 } 728 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_backend/codegen/task.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698