mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 20:21:21 +00:00
[dart2js] Replace phi with controlling condition
Rewrite `phi(true, false)` to the controlling condition. This patchset comparison shows the general effect: https://dart-review.googlesource.com/c/sdk/+/340065/2..3/pkg/compiler/test/codegen/data/phi_to_condition_test.dart This change is a partial remedy for http://dartbug.com/54115 Issue: #54115 Change-Id: Ibcc5d17f6c4c8ad9600840ec106f84edcd008e4a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/340065 Reviewed-by: Nate Biggs <natebiggs@google.com> Commit-Queue: Stephen Adams <sra@google.com>
This commit is contained in:
parent
e00ab8c3ce
commit
75b1973041
|
@ -333,13 +333,64 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simplify some CFG diamonds to equivalent expressions.
|
// Simplify some CFG diamonds to equivalent expressions.
|
||||||
simplifyPhis(HBasicBlock block) {
|
void simplifyPhis(HBasicBlock block) {
|
||||||
// Is [block] the join point for a simple diamond that generates a single
|
|
||||||
// phi node?
|
|
||||||
if (block.phis.isEmpty) return;
|
|
||||||
HPhi phi = block.phis.first as HPhi;
|
|
||||||
if (phi.next != null) return;
|
|
||||||
if (block.predecessors.length != 2) return;
|
if (block.predecessors.length != 2) return;
|
||||||
|
|
||||||
|
// Do 'statement' simplifications first, as they might reduce the number of
|
||||||
|
// phis to one, enabling an 'expression' simplification.
|
||||||
|
HInstruction? phi = block.phis.first;
|
||||||
|
while (phi != null) {
|
||||||
|
final next = phi.next;
|
||||||
|
simplifyStatementPhi(block, phi as HPhi);
|
||||||
|
phi = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
phi = block.phis.first;
|
||||||
|
if (phi != null && phi.next == null) {
|
||||||
|
simplifyExpressionPhi(block, phi as HPhi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Simplify a single phi when there are possibly other phis (i.e. the result
|
||||||
|
/// might not be an expression).
|
||||||
|
void simplifyStatementPhi(HBasicBlock block, HPhi phi) {
|
||||||
|
HBasicBlock dominator = block.dominator!;
|
||||||
|
|
||||||
|
// Extract the controlling condition.
|
||||||
|
final controlFlow = dominator.last;
|
||||||
|
if (controlFlow is! HIf) return;
|
||||||
|
HInstruction condition = controlFlow.inputs.single;
|
||||||
|
|
||||||
|
if (condition.isBoolean(_abstractValueDomain).isPotentiallyFalse) return;
|
||||||
|
|
||||||
|
// condition ? true : false --> condition
|
||||||
|
// condition ? condition : false --> condition
|
||||||
|
// condition ? true : condition --> condition
|
||||||
|
final left = phi.inputs[0];
|
||||||
|
final right = phi.inputs[1];
|
||||||
|
if ((_isBoolConstant(left, true) || left == condition) &&
|
||||||
|
(_isBoolConstant(right, false) || right == condition)) {
|
||||||
|
block.rewrite(phi, condition);
|
||||||
|
block.removePhi(phi);
|
||||||
|
condition.sourceElement ??= phi.sourceElement;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// condition ? false : true --> !condition
|
||||||
|
if (_isBoolConstant(left, false) && _isBoolConstant(right, true)) {
|
||||||
|
HInstruction replacement = HNot(condition, _abstractValueDomain.boolType)
|
||||||
|
..sourceElement = phi.sourceElement
|
||||||
|
..sourceInformation = phi.sourceInformation;
|
||||||
|
block.addAtEntry(replacement);
|
||||||
|
block.rewrite(phi, replacement);
|
||||||
|
block.removePhi(phi);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Simplify some CFG diamonds to equivalent expressions.
|
||||||
|
void simplifyExpressionPhi(HBasicBlock block, HPhi phi) {
|
||||||
|
// Is [block] the join point for a simple diamond?
|
||||||
assert(phi.inputs.length == 2);
|
assert(phi.inputs.length == 2);
|
||||||
HBasicBlock b1 = block.predecessors[0];
|
HBasicBlock b1 = block.predecessors[0];
|
||||||
HBasicBlock b2 = block.predecessors[1];
|
HBasicBlock b2 = block.predecessors[1];
|
||||||
|
@ -350,6 +401,7 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
|
||||||
final controlFlow = dominator.last;
|
final controlFlow = dominator.last;
|
||||||
if (controlFlow is! HIf) return;
|
if (controlFlow is! HIf) return;
|
||||||
HInstruction test = controlFlow.inputs.single;
|
HInstruction test = controlFlow.inputs.single;
|
||||||
|
|
||||||
if (test.usedBy.length > 1) return;
|
if (test.usedBy.length > 1) return;
|
||||||
|
|
||||||
bool negated = false;
|
bool negated = false;
|
||||||
|
@ -396,7 +448,7 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
|
||||||
block.removePhi(phi);
|
block.removePhi(phi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// If 'x'is nullable boolean,
|
// If 'x' is nullable boolean,
|
||||||
//
|
//
|
||||||
// x == null ? true : x ---> !(x == false)
|
// x == null ? true : x ---> !(x == false)
|
||||||
//
|
//
|
||||||
|
|
|
@ -59,6 +59,20 @@ int noopOr(int a) {
|
||||||
return (a == 1 || a == 3 || a == 5 || a == 7 || a == 9) ? 100 : 100;
|
return (a == 1 || a == 3 || a == 5 || a == 7 || a == 9) ? 100 : 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*member: constantFoldedControlFlow3:function(a) {
|
||||||
|
return a;
|
||||||
|
}*/
|
||||||
|
bool constantFoldedControlFlow3(bool a) {
|
||||||
|
return a && 1 == 1 && 2 == 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*member: constantFoldedControlFlow4:function(a) {
|
||||||
|
return a;
|
||||||
|
}*/
|
||||||
|
bool constantFoldedControlFlow4(bool a) {
|
||||||
|
return 1 == 1 && a && 2 == 2;
|
||||||
|
}
|
||||||
|
|
||||||
// Problem cases.
|
// Problem cases.
|
||||||
//
|
//
|
||||||
// Move the following cases above this comment when the code quality improves.
|
// Move the following cases above this comment when the code quality improves.
|
||||||
|
@ -130,29 +144,15 @@ bool constantFoldedControlFlow1(bool a, bool b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*member: constantFoldedControlFlow2:function(a, b) {
|
/*member: constantFoldedControlFlow2:function(a, b) {
|
||||||
return a && b && true;
|
|
||||||
}*/
|
|
||||||
bool constantFoldedControlFlow2(bool a, bool b) {
|
|
||||||
return 1 == 1 && a && 2 == 2 && b && 3 == 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*member: constantFoldedControlFlow3:function(a) {
|
|
||||||
var t1;
|
var t1;
|
||||||
if (a)
|
if (a)
|
||||||
t1 = true;
|
t1 = b;
|
||||||
else
|
else
|
||||||
t1 = false;
|
t1 = false;
|
||||||
return t1;
|
return t1;
|
||||||
}*/
|
}*/
|
||||||
bool constantFoldedControlFlow3(bool a) {
|
bool constantFoldedControlFlow2(bool a, bool b) {
|
||||||
return a && 1 == 1 && 2 == 2;
|
return 1 == 1 && a && 2 == 2 && b && 3 == 3;
|
||||||
}
|
|
||||||
|
|
||||||
/*member: constantFoldedControlFlow4:function(a) {
|
|
||||||
return a && true;
|
|
||||||
}*/
|
|
||||||
bool constantFoldedControlFlow4(bool a) {
|
|
||||||
return 1 == 1 && a && 2 == 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@pragma('dart2js:disable-inlining')
|
@pragma('dart2js:disable-inlining')
|
||||||
|
|
29
pkg/compiler/test/codegen/data/phi_to_condition_test.dart
Normal file
29
pkg/compiler/test/codegen/data/phi_to_condition_test.dart
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
||||||
|
// for details. All rights reserved. Use of this source code is governed by a
|
||||||
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@pragma('dart2js:never-inline')
|
||||||
|
/*member: foo1:function(a, b) {
|
||||||
|
var changed = a !== b;
|
||||||
|
if (changed)
|
||||||
|
A.log("changed");
|
||||||
|
return changed;
|
||||||
|
}*/
|
||||||
|
foo1(int a, int b) {
|
||||||
|
bool changed = false;
|
||||||
|
if (a != b) {
|
||||||
|
changed = true;
|
||||||
|
log('changed');
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@pragma('dart2js:never-inline')
|
||||||
|
/*member: log:ignore*/
|
||||||
|
void log(String s) {}
|
||||||
|
|
||||||
|
/*member: main:ignore*/
|
||||||
|
main() {
|
||||||
|
foo1(1, 2);
|
||||||
|
foo1(2, 1);
|
||||||
|
}
|
Loading…
Reference in a new issue