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

Side by Side Diff: pkg/compiler/lib/src/ssa/optimize.dart

Issue 1413213004: Move remaining helpers to BackendHelpers (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 1 month 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 | « pkg/compiler/lib/src/ssa/nodes.dart ('k') | pkg/compiler/lib/src/ssa/types_propagation.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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 part of ssa; 5 part of ssa;
6 6
7 abstract class OptimizationPhase { 7 abstract class OptimizationPhase {
8 String get name; 8 String get name;
9 void visitGraph(HGraph graph); 9 void visitGraph(HGraph graph);
10 } 10 }
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 /// of identifying gvn-able lengths and mis-identifies some unions of fixed 104 /// of identifying gvn-able lengths and mis-identifies some unions of fixed
105 /// length indexables (see TODO) as not fixed length. 105 /// length indexables (see TODO) as not fixed length.
106 bool isFixedLength(mask, Compiler compiler) { 106 bool isFixedLength(mask, Compiler compiler) {
107 ClassWorld classWorld = compiler.world; 107 ClassWorld classWorld = compiler.world;
108 JavaScriptBackend backend = compiler.backend; 108 JavaScriptBackend backend = compiler.backend;
109 if (mask.isContainer && mask.length != null) { 109 if (mask.isContainer && mask.length != null) {
110 // A container on which we have inferred the length. 110 // A container on which we have inferred the length.
111 return true; 111 return true;
112 } 112 }
113 // TODO(sra): Recognize any combination of fixed length indexables. 113 // TODO(sra): Recognize any combination of fixed length indexables.
114 if (mask.containsOnly(backend.jsFixedArrayClass) || 114 if (mask.containsOnly(backend.helpers.jsFixedArrayClass) ||
115 mask.containsOnly(backend.jsUnmodifiableArrayClass) || 115 mask.containsOnly(backend.helpers.jsUnmodifiableArrayClass) ||
116 mask.containsOnlyString(classWorld) || 116 mask.containsOnlyString(classWorld) ||
117 backend.isTypedArray(mask)) { 117 backend.isTypedArray(mask)) {
118 return true; 118 return true;
119 } 119 }
120 return false; 120 return false;
121 } 121 }
122 122
123 /** 123 /**
124 * If both inputs to known operations are available execute the operation at 124 * If both inputs to known operations are available execute the operation at
125 * compile-time. 125 * compile-time.
(...skipping 14 matching lines...) Expand all
140 Compiler get compiler => backend.compiler; 140 Compiler get compiler => backend.compiler;
141 final SsaOptimizerTask optimizer; 141 final SsaOptimizerTask optimizer;
142 142
143 SsaInstructionSimplifier(this.constantSystem, 143 SsaInstructionSimplifier(this.constantSystem,
144 this.backend, 144 this.backend,
145 this.optimizer, 145 this.optimizer,
146 this.work); 146 this.work);
147 147
148 CoreClasses get coreClasses => compiler.coreClasses; 148 CoreClasses get coreClasses => compiler.coreClasses;
149 149
150 BackendHelpers get helpers => backend.helpers;
151
150 void visitGraph(HGraph visitee) { 152 void visitGraph(HGraph visitee) {
151 graph = visitee; 153 graph = visitee;
152 visitDominatorTree(visitee); 154 visitDominatorTree(visitee);
153 } 155 }
154 156
155 visitBasicBlock(HBasicBlock block) { 157 visitBasicBlock(HBasicBlock block) {
156 HInstruction instruction = block.first; 158 HInstruction instruction = block.first;
157 while (instruction != null) { 159 while (instruction != null) {
158 HInstruction next = instruction.next; 160 HInstruction next = instruction.next;
159 HInstruction replacement = instruction.accept(this); 161 HInstruction replacement = instruction.accept(this);
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
245 247
246 // If the code is unreachable, remove the HBoolify. This can happen when 248 // If the code is unreachable, remove the HBoolify. This can happen when
247 // there is a throw expression in a short-circuit conditional. Removing the 249 // there is a throw expression in a short-circuit conditional. Removing the
248 // unreachable HBoolify makes it easier to reconstruct the short-circuit 250 // unreachable HBoolify makes it easier to reconstruct the short-circuit
249 // operation. 251 // operation.
250 if (input.instructionType.isEmpty && !input.instructionType.isNullable) 252 if (input.instructionType.isEmpty && !input.instructionType.isNullable)
251 return input; 253 return input;
252 254
253 // All values that cannot be 'true' are boolified to false. 255 // All values that cannot be 'true' are boolified to false.
254 TypeMask mask = input.instructionType; 256 TypeMask mask = input.instructionType;
255 if (!mask.contains(backend.jsBoolClass, compiler.world)) { 257 if (!mask.contains(helpers.jsBoolClass, compiler.world)) {
256 return graph.addConstantBool(false, compiler); 258 return graph.addConstantBool(false, compiler);
257 } 259 }
258 return node; 260 return node;
259 } 261 }
260 262
261 HInstruction visitNot(HNot node) { 263 HInstruction visitNot(HNot node) {
262 List<HInstruction> inputs = node.inputs; 264 List<HInstruction> inputs = node.inputs;
263 assert(inputs.length == 1); 265 assert(inputs.length == 1);
264 HInstruction input = inputs[0]; 266 HInstruction input = inputs[0];
265 if (input is HConstant) { 267 if (input is HConstant) {
(...skipping 26 matching lines...) Expand all
292 if (actualReceiver.isIndexablePrimitive(compiler)) { 294 if (actualReceiver.isIndexablePrimitive(compiler)) {
293 if (actualReceiver.isConstantString()) { 295 if (actualReceiver.isConstantString()) {
294 HConstant constantInput = actualReceiver; 296 HConstant constantInput = actualReceiver;
295 StringConstantValue constant = constantInput.constant; 297 StringConstantValue constant = constantInput.constant;
296 return graph.addConstantInt(constant.length, compiler); 298 return graph.addConstantInt(constant.length, compiler);
297 } else if (actualReceiver.isConstantList()) { 299 } else if (actualReceiver.isConstantList()) {
298 HConstant constantInput = actualReceiver; 300 HConstant constantInput = actualReceiver;
299 ListConstantValue constant = constantInput.constant; 301 ListConstantValue constant = constantInput.constant;
300 return graph.addConstantInt(constant.length, compiler); 302 return graph.addConstantInt(constant.length, compiler);
301 } 303 }
302 Element element = backend.jsIndexableLength; 304 Element element = helpers.jsIndexableLength;
303 bool isFixed = isFixedLength(actualReceiver.instructionType, compiler); 305 bool isFixed = isFixedLength(actualReceiver.instructionType, compiler);
304 TypeMask actualType = node.instructionType; 306 TypeMask actualType = node.instructionType;
305 ClassWorld classWorld = compiler.world; 307 ClassWorld classWorld = compiler.world;
306 TypeMask resultType = backend.positiveIntType; 308 TypeMask resultType = backend.positiveIntType;
307 // If we already have computed a more specific type, keep that type. 309 // If we already have computed a more specific type, keep that type.
308 if (HInstruction.isInstanceOf( 310 if (HInstruction.isInstanceOf(
309 actualType, backend.jsUInt31Class, classWorld)) { 311 actualType, helpers.jsUInt31Class, classWorld)) {
310 resultType = backend.uint31Type; 312 resultType = backend.uint31Type;
311 } else if (HInstruction.isInstanceOf( 313 } else if (HInstruction.isInstanceOf(
312 actualType, backend.jsUInt32Class, classWorld)) { 314 actualType, helpers.jsUInt32Class, classWorld)) {
313 resultType = backend.uint32Type; 315 resultType = backend.uint32Type;
314 } 316 }
315 HFieldGet result = new HFieldGet( 317 HFieldGet result = new HFieldGet(
316 element, actualReceiver, resultType, 318 element, actualReceiver, resultType,
317 isAssignable: !isFixed); 319 isAssignable: !isFixed);
318 return result; 320 return result;
319 } else if (actualReceiver.isConstantMap()) { 321 } else if (actualReceiver.isConstantMap()) {
320 HConstant constantInput = actualReceiver; 322 HConstant constantInput = actualReceiver;
321 MapConstantValue constant = constantInput.constant; 323 MapConstantValue constant = constantInput.constant;
322 return graph.addConstantInt(constant.length, compiler); 324 return graph.addConstantInt(constant.length, compiler);
(...skipping 23 matching lines...) Expand all
346 World world = compiler.world; 348 World world = compiler.world;
347 349
348 bool applies(Element element) { 350 bool applies(Element element) {
349 return selector.applies(element, world) && 351 return selector.applies(element, world) &&
350 (mask == null || mask.canHit(element, selector, world)); 352 (mask == null || mask.canHit(element, selector, world));
351 } 353 }
352 354
353 if (selector.isCall || selector.isOperator) { 355 if (selector.isCall || selector.isOperator) {
354 Element target; 356 Element target;
355 if (input.isExtendableArray(compiler)) { 357 if (input.isExtendableArray(compiler)) {
356 if (applies(backend.jsArrayRemoveLast)) { 358 if (applies(helpers.jsArrayRemoveLast)) {
357 target = backend.jsArrayRemoveLast; 359 target = helpers.jsArrayRemoveLast;
358 } else if (applies(backend.jsArrayAdd)) { 360 } else if (applies(helpers.jsArrayAdd)) {
359 // The codegen special cases array calls, but does not 361 // The codegen special cases array calls, but does not
360 // inline argument type checks. 362 // inline argument type checks.
361 if (!compiler.enableTypeAssertions) { 363 if (!compiler.enableTypeAssertions) {
362 target = backend.jsArrayAdd; 364 target = helpers.jsArrayAdd;
363 } 365 }
364 } 366 }
365 } else if (input.isStringOrNull(compiler)) { 367 } else if (input.isStringOrNull(compiler)) {
366 if (applies(backend.jsStringSplit)) { 368 if (applies(helpers.jsStringSplit)) {
367 HInstruction argument = node.inputs[2]; 369 HInstruction argument = node.inputs[2];
368 if (argument.isString(compiler)) { 370 if (argument.isString(compiler)) {
369 target = backend.jsStringSplit; 371 target = helpers.jsStringSplit;
370 } 372 }
371 } else if (applies(backend.jsStringOperatorAdd)) { 373 } else if (applies(helpers.jsStringOperatorAdd)) {
372 // `operator+` is turned into a JavaScript '+' so we need to 374 // `operator+` is turned into a JavaScript '+' so we need to
373 // make sure the receiver and the argument are not null. 375 // make sure the receiver and the argument are not null.
374 // TODO(sra): Do this via [node.specializer]. 376 // TODO(sra): Do this via [node.specializer].
375 HInstruction argument = node.inputs[2]; 377 HInstruction argument = node.inputs[2];
376 if (argument.isString(compiler) 378 if (argument.isString(compiler)
377 && !input.canBeNull()) { 379 && !input.canBeNull()) {
378 return new HStringConcat(input, argument, null, 380 return new HStringConcat(input, argument, null,
379 node.instructionType); 381 node.instructionType);
380 } 382 }
381 } else if (applies(backend.jsStringToString) 383 } else if (applies(helpers.jsStringToString)
382 && !input.canBeNull()) { 384 && !input.canBeNull()) {
383 return input; 385 return input;
384 } 386 }
385 } 387 }
386 if (target != null) { 388 if (target != null) {
387 // TODO(ngeoffray): There is a strong dependency between codegen 389 // TODO(ngeoffray): There is a strong dependency between codegen
388 // and this optimization that the dynamic invoke does not need an 390 // and this optimization that the dynamic invoke does not need an
389 // interceptor. We currently need to keep a 391 // interceptor. We currently need to keep a
390 // HInvokeDynamicMethod and not create a HForeign because 392 // HInvokeDynamicMethod and not create a HForeign because
391 // HForeign is too opaque for the SsaCheckInserter (that adds a 393 // HForeign is too opaque for the SsaCheckInserter (that adds a
392 // bounds check on removeLast). Once we start inlining, the 394 // bounds check on removeLast). Once we start inlining, the
393 // bounds check will become explicit, so we won't need this 395 // bounds check will become explicit, so we won't need this
394 // optimization. 396 // optimization.
395 HInvokeDynamicMethod result = new HInvokeDynamicMethod( 397 HInvokeDynamicMethod result = new HInvokeDynamicMethod(
396 node.selector, node.mask, 398 node.selector, node.mask,
397 node.inputs.sublist(1), node.instructionType); 399 node.inputs.sublist(1), node.instructionType);
398 result.element = target; 400 result.element = target;
399 return result; 401 return result;
400 } 402 }
401 } else if (selector.isGetter) { 403 } else if (selector.isGetter) {
402 if (selector.applies(backend.jsIndexableLength, world)) { 404 if (selector.applies(helpers.jsIndexableLength, world)) {
403 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node); 405 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node);
404 if (optimized != null) return optimized; 406 if (optimized != null) return optimized;
405 } 407 }
406 } 408 }
407 409
408 return node; 410 return node;
409 } 411 }
410 412
411 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { 413 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
412 propagateConstantValueToUses(node); 414 propagateConstantValueToUses(node);
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after
776 778
777 VariableElement findConcreteFieldForDynamicAccess(HInstruction receiver, 779 VariableElement findConcreteFieldForDynamicAccess(HInstruction receiver,
778 Selector selector) { 780 Selector selector) {
779 TypeMask receiverType = receiver.instructionType; 781 TypeMask receiverType = receiver.instructionType;
780 return compiler.world.locateSingleField(selector, receiverType); 782 return compiler.world.locateSingleField(selector, receiverType);
781 } 783 }
782 784
783 HInstruction visitFieldGet(HFieldGet node) { 785 HInstruction visitFieldGet(HFieldGet node) {
784 if (node.isNullCheck) return node; 786 if (node.isNullCheck) return node;
785 var receiver = node.receiver; 787 var receiver = node.receiver;
786 if (node.element == backend.jsIndexableLength) { 788 if (node.element == helpers.jsIndexableLength) {
787 JavaScriptItemCompilationContext context = work.compilationContext; 789 JavaScriptItemCompilationContext context = work.compilationContext;
788 if (context.allocatedFixedLists.contains(receiver)) { 790 if (context.allocatedFixedLists.contains(receiver)) {
789 // TODO(ngeoffray): checking if the second input is an integer 791 // TODO(ngeoffray): checking if the second input is an integer
790 // should not be necessary but it currently makes it easier for 792 // should not be necessary but it currently makes it easier for
791 // other optimizations to reason about a fixed length constructor 793 // other optimizations to reason about a fixed length constructor
792 // that we know takes an int. 794 // that we know takes an int.
793 if (receiver.inputs[0].isInteger(compiler)) { 795 if (receiver.inputs[0].isInteger(compiler)) {
794 return receiver.inputs[0]; 796 return receiver.inputs[0];
795 } 797 }
796 } else if (receiver.isConstantList() || receiver.isConstantString()) { 798 } else if (receiver.isConstantList() || receiver.isConstantString()) {
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
998 final bool trustPrimitives; 1000 final bool trustPrimitives;
999 final JavaScriptBackend backend; 1001 final JavaScriptBackend backend;
1000 final String name = "SsaCheckInserter"; 1002 final String name = "SsaCheckInserter";
1001 HGraph graph; 1003 HGraph graph;
1002 1004
1003 SsaCheckInserter(this.trustPrimitives, 1005 SsaCheckInserter(this.trustPrimitives,
1004 this.backend, 1006 this.backend,
1005 this.work, 1007 this.work,
1006 this.boundsChecked); 1008 this.boundsChecked);
1007 1009
1010 BackendHelpers get helpers => backend.helpers;
1011
1008 void visitGraph(HGraph graph) { 1012 void visitGraph(HGraph graph) {
1009 this.graph = graph; 1013 this.graph = graph;
1010 1014
1011 // In --trust-primitives mode we don't add bounds checks. This is better 1015 // In --trust-primitives mode we don't add bounds checks. This is better
1012 // than trying to remove them later as the limit expression would become 1016 // than trying to remove them later as the limit expression would become
1013 // dead and require DCE. 1017 // dead and require DCE.
1014 if (trustPrimitives) return; 1018 if (trustPrimitives) return;
1015 1019
1016 visitDominatorTree(graph); 1020 visitDominatorTree(graph);
1017 } 1021 }
1018 1022
1019 void visitBasicBlock(HBasicBlock block) { 1023 void visitBasicBlock(HBasicBlock block) {
1020 HInstruction instruction = block.first; 1024 HInstruction instruction = block.first;
1021 while (instruction != null) { 1025 while (instruction != null) {
1022 HInstruction next = instruction.next; 1026 HInstruction next = instruction.next;
1023 instruction = instruction.accept(this); 1027 instruction = instruction.accept(this);
1024 instruction = next; 1028 instruction = next;
1025 } 1029 }
1026 } 1030 }
1027 1031
1028 HBoundsCheck insertBoundsCheck(HInstruction indexNode, 1032 HBoundsCheck insertBoundsCheck(HInstruction indexNode,
1029 HInstruction array, 1033 HInstruction array,
1030 HInstruction indexArgument) { 1034 HInstruction indexArgument) {
1031 Compiler compiler = backend.compiler; 1035 Compiler compiler = backend.compiler;
1032 HFieldGet length = new HFieldGet( 1036 HFieldGet length = new HFieldGet(
1033 backend.jsIndexableLength, array, backend.positiveIntType, 1037 helpers.jsIndexableLength, array, backend.positiveIntType,
1034 isAssignable: !isFixedLength(array.instructionType, compiler)); 1038 isAssignable: !isFixedLength(array.instructionType, compiler));
1035 indexNode.block.addBefore(indexNode, length); 1039 indexNode.block.addBefore(indexNode, length);
1036 1040
1037 TypeMask type = indexArgument.isPositiveInteger(compiler) 1041 TypeMask type = indexArgument.isPositiveInteger(compiler)
1038 ? indexArgument.instructionType 1042 ? indexArgument.instructionType
1039 : backend.positiveIntType; 1043 : backend.positiveIntType;
1040 HBoundsCheck check = new HBoundsCheck( 1044 HBoundsCheck check = new HBoundsCheck(
1041 indexArgument, length, array, type); 1045 indexArgument, length, array, type);
1042 indexNode.block.addBefore(indexNode, check); 1046 indexNode.block.addBefore(indexNode, check);
1043 // If the index input to the bounds check was not known to be an integer 1047 // If the index input to the bounds check was not known to be an integer
(...skipping 18 matching lines...) Expand all
1062 1066
1063 void visitIndexAssign(HIndexAssign node) { 1067 void visitIndexAssign(HIndexAssign node) {
1064 if (boundsChecked.contains(node)) return; 1068 if (boundsChecked.contains(node)) return;
1065 HInstruction index = node.index; 1069 HInstruction index = node.index;
1066 index = insertBoundsCheck(node, node.receiver, index); 1070 index = insertBoundsCheck(node, node.receiver, index);
1067 } 1071 }
1068 1072
1069 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) { 1073 void visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
1070 Element element = node.element; 1074 Element element = node.element;
1071 if (node.isInterceptedCall) return; 1075 if (node.isInterceptedCall) return;
1072 if (element != backend.jsArrayRemoveLast) return; 1076 if (element != helpers.jsArrayRemoveLast) return;
1073 if (boundsChecked.contains(node)) return; 1077 if (boundsChecked.contains(node)) return;
1074 // `0` is the index we want to check, but we want to report `-1`, as if we 1078 // `0` is the index we want to check, but we want to report `-1`, as if we
1075 // executed `a[a.length-1]` 1079 // executed `a[a.length-1]`
1076 HBoundsCheck check = insertBoundsCheck( 1080 HBoundsCheck check = insertBoundsCheck(
1077 node, node.receiver, graph.addConstantInt(0, backend.compiler)); 1081 node, node.receiver, graph.addConstantInt(0, backend.compiler));
1078 HInstruction minusOne = graph.addConstantInt(-1, backend.compiler); 1082 HInstruction minusOne = graph.addConstantInt(-1, backend.compiler);
1079 check.inputs.add(minusOne); 1083 check.inputs.add(minusOne);
1080 minusOne.usedBy.add(check); 1084 minusOne.usedBy.add(check);
1081 } 1085 }
1082 } 1086 }
(...skipping 1315 matching lines...) Expand 10 before | Expand all | Expand 10 after
2398 2402
2399 keyedValues.forEach((receiver, values) { 2403 keyedValues.forEach((receiver, values) {
2400 result.keyedValues[receiver] = 2404 result.keyedValues[receiver] =
2401 new Map<HInstruction, HInstruction>.from(values); 2405 new Map<HInstruction, HInstruction>.from(values);
2402 }); 2406 });
2403 2407
2404 result.nonEscapingReceivers.addAll(nonEscapingReceivers); 2408 result.nonEscapingReceivers.addAll(nonEscapingReceivers);
2405 return result; 2409 return result;
2406 } 2410 }
2407 } 2411 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/ssa/nodes.dart ('k') | pkg/compiler/lib/src/ssa/types_propagation.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698