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

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

Issue 1578963002: dart2js cps: Hoist unsafe expressions from loop entry. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Update test expectations 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 | tests/compiler/dart2js/cps_ir/expected/codeUnitAt_2.js » ('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;
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 // environment while processing the body of the LetPrim. 169 // environment while processing the body of the LetPrim.
170 environment[gvn] = prim; 170 environment[gvn] = prim;
171 pushAction(() { 171 pushAction(() {
172 assert(environment[gvn] == prim); 172 assert(environment[gvn] == prim);
173 environment[gvn] = existing; 173 environment[gvn] = existing;
174 }); 174 });
175 175
176 return next; 176 return next;
177 } 177 }
178 178
179 bool isFirstImpureExpressionInLoop(Expression exp) {
180 InteriorNode node = exp.parent;
181 for (; node is Expression; node = node.parent) {
182 if (node is LetPrim && node.primitive.isSafeForElimination) {
183 continue;
184 }
185 if (node is LetCont) {
186 continue;
187 }
188 return false;
189 }
190 return node == currentLoopHeader;
191 }
192
193 bool isHoistablePrimitive(Primitive prim) {
194 if (prim.isSafeForElimination) return true;
195 if (prim is NullCheck ||
196 prim is BoundsCheck ||
197 prim is GetLength ||
198 prim is GetField ||
199 prim is GetIndex) {
200 // Expressions that potentially throw but have no other effects can be
201 // hoisted if they occur as the first impure expression in a loop.
202 // Note regarding BoundsCheck: the current array length is an input to
203 // check, so the check itself has no heap dependency. It will only be
204 // hoisted if the length was hoisted.
205 // TODO(asgerf): In general we could hoist these out of multiple loops,
206 // but the trick we use here only works for one loop level.
207 return isFirstImpureExpressionInLoop(prim.parent);
208 }
209 return false;
210 }
211
179 /// Try to hoist the binding of [prim] out of loops. Returns `true` if it was 212 /// Try to hoist the binding of [prim] out of loops. Returns `true` if it was
180 /// hoisted or marked as a trivial hoist-on-demand primitive. 213 /// hoisted or marked as a trivial hoist-on-demand primitive.
181 bool tryToHoistOutOfLoop(Primitive prim, int gvn) { 214 bool tryToHoistOutOfLoop(Primitive prim, int gvn) {
182 // Do not hoist primitives with side effects.
183 if (!prim.isSafeForElimination) return false;
184
185 // Bail out fast if the primitive is not inside a loop. 215 // Bail out fast if the primitive is not inside a loop.
186 if (currentLoopHeader == null) return false; 216 if (currentLoopHeader == null) return false;
187 217
218 // Do not hoist primitives with side effects.
219 if (!isHoistablePrimitive(prim)) return false;
220
188 LetPrim letPrim = prim.parent; 221 LetPrim letPrim = prim.parent;
189 222
190 // Find the depth of the outermost scope where we can bind the primitive 223 // Find the depth of the outermost scope where we can bind the primitive
191 // without bringing a reference out of scope. 0 is the depth of the 224 // without bringing a reference out of scope. 0 is the depth of the
192 // top-level scope. 225 // top-level scope.
193 int hoistDepth = 0; 226 int hoistDepth = 0;
194 List<Primitive> inputsHoistedOnDemand = <Primitive>[]; 227 List<Primitive> inputsHoistedOnDemand = <Primitive>[];
195 InputVisitor.forEach(prim, (Reference ref) { 228 InputVisitor.forEach(prim, (Reference ref) {
196 Primitive input = ref.definition; 229 Primitive input = ref.definition;
197 if (canIgnoreRefinementGuards(prim)) { 230 if (canIgnoreRefinementGuards(prim)) {
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 return element.isField && world.fieldNeverChanges(element) || 353 return element.isField && world.fieldNeverChanges(element) ||
321 element.isFunction; 354 element.isFunction;
322 } 355 }
323 356
324 bool isImmutableLength(GetLength length) { 357 bool isImmutableLength(GetLength length) {
325 return types.isDefinitelyFixedLengthIndexable(length.object.definition.type, 358 return types.isDefinitelyFixedLengthIndexable(length.object.definition.type,
326 allowNull: true); 359 allowNull: true);
327 } 360 }
328 361
329 /// Assuming [prim] has no side effects, returns true if it can safely 362 /// Assuming [prim] has no side effects, returns true if it can safely
330 /// be hoisted out of [loop] without changing its value. 363 /// be hoisted out of [loop] without changing its value or changing the timing
364 /// of a thrown exception.
331 bool canHoistHeapDependencyOutOfLoop(Primitive prim, Continuation loop) { 365 bool canHoistHeapDependencyOutOfLoop(Primitive prim, Continuation loop) {
332 assert(prim.isSafeForElimination); 366 // If the primitive might throw, we have to check that it is the first
367 // impure expression in the loop. This has already been checked if
368 // [loop] is the current loop header, but for other loops we just give up.
369 if (!prim.isSafeForElimination && loop != currentLoopHeader) {
370 return false;
371 }
333 if (prim is GetLength && !isImmutableLength(prim)) { 372 if (prim is GetLength && !isImmutableLength(prim)) {
334 return !loopEffects.loopChangesLength(loop); 373 return !loopEffects.loopChangesLength(loop);
335 } else if (prim is GetField && !isImmutable(prim.field)) { 374 } else if (prim is GetField && !isImmutable(prim.field)) {
336 return !loopEffects.getSideEffectsInLoop(loop).changesInstanceProperty(); 375 return !loopEffects.getSideEffectsInLoop(loop).changesInstanceProperty();
337 } else if (prim is GetStatic && !isImmutable(prim.element)) { 376 } else if (prim is GetStatic && !isImmutable(prim.element)) {
338 return !loopEffects.getSideEffectsInLoop(loop).changesStaticProperty(); 377 return !loopEffects.getSideEffectsInLoop(loop).changesStaticProperty();
339 } else if (prim is GetIndex) { 378 } else if (prim is GetIndex) {
340 return !loopEffects.getSideEffectsInLoop(loop).changesIndex(); 379 return !loopEffects.getSideEffectsInLoop(loop).changesIndex();
341 } else { 380 } else {
342 return true; 381 return true;
343 } 382 }
344 } 383 }
345 384
346
347 // ------------------ TRAVERSAL AND EFFECT NUMBERING --------------------- 385 // ------------------ TRAVERSAL AND EFFECT NUMBERING ---------------------
348 // 386 //
349 // These methods traverse the IR while updating the current effect numbers. 387 // These methods traverse the IR while updating the current effect numbers.
350 // They are not specific to GVN. 388 // They are not specific to GVN.
351 // 389 //
352 // TODO(asgerf): Avoid duplicated code for side effect analysis. 390 // TODO(asgerf): Avoid duplicated code for side effect analysis.
353 // Should be easier to fix once primitives and call expressions are the same. 391 // Should be easier to fix once primitives and call expressions are the same.
354 392
355 void addSideEffects(SideEffects fx, {bool length: true}) { 393 void addSideEffects(SideEffects fx, {bool length: true}) {
356 if (fx.changesInstanceProperty()) { 394 if (fx.changesInstanceProperty()) {
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after
722 760
723 @override 761 @override
724 processReference(Reference ref) { 762 processReference(Reference ref) {
725 callback(ref); 763 callback(ref);
726 } 764 }
727 765
728 static void forEach(Primitive node, ReferenceCallback callback) { 766 static void forEach(Primitive node, ReferenceCallback callback) {
729 new InputVisitor(callback).visit(node); 767 new InputVisitor(callback).visit(node);
730 } 768 }
731 } 769 }
OLDNEW
« no previous file with comments | « no previous file | tests/compiler/dart2js/cps_ir/expected/codeUnitAt_2.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698