mirror of
https://github.com/dart-lang/sdk
synced 2024-10-03 01:14:16 +00:00
[dart2js] Constant-fold const record accesses
I noticed that dart2js generated poor code for `(a, b) = (1, 2)`. This is due to an oversight in not constant-folding record field loads. Change-Id: Iac110d8c3373d7673c21494fc467f7fcb400de1d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/371505 Commit-Queue: Stephen Adams <sra@google.com> Reviewed-by: Mayank Patke <fishythefish@google.com>
This commit is contained in:
parent
8c918ffda3
commit
77496338dc
|
@ -122,7 +122,7 @@ class CommonMasks with AbstractValueDomain {
|
|||
// subtypes of Record or (2) several live subtypes of Record. Everything
|
||||
// 'works' for the similar interface `Function` because there are multiple
|
||||
// live subclasses of `Closure`.
|
||||
late final TypeMask recordType = dynamicType;
|
||||
late final TypeMask recordType = nonNullType;
|
||||
|
||||
@override
|
||||
late final TypeMask listType =
|
||||
|
|
|
@ -1559,6 +1559,25 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
|
|||
return _graph.addConstant(value, _closedWorld);
|
||||
}
|
||||
}
|
||||
if (constant is RecordConstantValue) {
|
||||
final recordData = _closedWorld.recordData;
|
||||
final shape = constant.shape;
|
||||
final representation = recordData.representationForShape(shape);
|
||||
if (representation != null) {
|
||||
// The `representation` does not have a method to convert a field into
|
||||
// a record-index, so look at all the possible access paths to find
|
||||
// one that matches the field. Although this is 'slow' (1) only short
|
||||
// records have direct fields (longer ones use arrays), and (2) we
|
||||
// should always find a matching path, so the search will not be
|
||||
// repeated in later phases.
|
||||
for (int i = 0; i < constant.shape.fieldCount; i++) {
|
||||
final path = recordData.pathForAccess(shape, i);
|
||||
if (path.field == node.element && path.index == null) {
|
||||
return _graph.addConstant(constant.values[i], _closedWorld);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
|
@ -1650,6 +1669,38 @@ class SsaInstructionSimplifier extends HBaseVisitor<HInstruction>
|
|||
return _graph.addConstant(foldedValue, _closedWorld);
|
||||
}
|
||||
}
|
||||
} else if (receiver is HFieldGet) {
|
||||
// Match the access path `(constant_record._values)[i]` for 'long' records
|
||||
// where the record fields are stored in an Array (the `_RecordN` family
|
||||
// of representations).
|
||||
final receiver2 = receiver.receiver;
|
||||
if (receiver2 is HConstant) {
|
||||
final constant = receiver2.constant;
|
||||
if (constant is RecordConstantValue) {
|
||||
HInstruction index = node.index;
|
||||
if (index is HConstant) {
|
||||
final constantIndex = index.constant;
|
||||
if (constantIndex is IntConstantValue && constantIndex.isUInt31()) {
|
||||
int indexValue = constantIndex.intValue.toInt();
|
||||
final recordData = _closedWorld.recordData;
|
||||
final shape = constant.shape;
|
||||
final representation = recordData.representationForShape(shape);
|
||||
if (representation != null) {
|
||||
// We assume that the record index is going to be the same as
|
||||
// the HIndex index. If not (for example, we put the shape in
|
||||
// the first slot of the array, offsetting the record field
|
||||
// indexes), the codegen test will fail.
|
||||
final path = recordData.pathForAccess(shape, indexValue);
|
||||
if (path.field == receiver.element &&
|
||||
path.index == indexValue) {
|
||||
return _graph.addConstant(
|
||||
constant.values[indexValue], _closedWorld);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
|
51
pkg/compiler/test/codegen/data/record_constant_folding.dart
Normal file
51
pkg/compiler/test/codegen/data/record_constant_folding.dart
Normal file
|
@ -0,0 +1,51 @@
|
|||
// 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.
|
||||
|
||||
const r3 = (1, 2, 3);
|
||||
const r9 = (1, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||
|
||||
@pragma('dart2js:never-inline')
|
||||
/*member: r3a:function() {
|
||||
return 123;
|
||||
}*/
|
||||
r3a() {
|
||||
int a, b, c;
|
||||
(a, b, c) = r3;
|
||||
return a * 100 + b * 10 + c;
|
||||
}
|
||||
|
||||
@pragma('dart2js:never-inline')
|
||||
/*member: r3b:function() {
|
||||
return 123;
|
||||
}*/
|
||||
r3b() {
|
||||
int a, b, c;
|
||||
(Z: a, A: b, P: c) = (A: 2, P: 3, Z: 1);
|
||||
return a * 100 + b * 10 + c;
|
||||
}
|
||||
|
||||
@pragma('dart2js:never-inline')
|
||||
/*member: r9a:function() {
|
||||
return 123456789;
|
||||
}*/
|
||||
r9a() {
|
||||
int a, b, c, d, e, f, g, h, i;
|
||||
(a, b, c, d, e, f, g, h, i) = r9;
|
||||
return a * 100000000 +
|
||||
b * 10000000 +
|
||||
c * 1000000 +
|
||||
d * 100000 +
|
||||
e * 10000 +
|
||||
f * 1000 +
|
||||
g * 100 +
|
||||
h * 10 +
|
||||
i;
|
||||
}
|
||||
|
||||
/*member: main:ignore*/
|
||||
main() {
|
||||
r3a();
|
||||
r3b();
|
||||
r9a();
|
||||
}
|
Loading…
Reference in a new issue