[vm/compiler] Fix materialization of Float32List

Before value is stored into Float32List, it is converted to 32-bit
float using DoubleToFloat instruction. If allocation sinking
eliminated the allocation of Float32List but we need to deoptimize,
the list is materialized and elements are filled. In such case,
we shouldn't perform double->float conversion as it already happened.

This change also updates the assertion in DoubleToFloatInstr::Canonicalize
which verifies that DoubleToFloat instruction can be used only
in certain cases.

TEST=tests/language/vm/allocation_sinking_arrays_test.dart
Fixes https://github.com/dart-lang/sdk/issues/45547

Change-Id: I9a1bd28a9fc09bccad6aa3c91a7880abd002f7c9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193831
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov 2021-04-02 01:36:28 +00:00 committed by commit-bot@chromium.org
parent 628193450a
commit 38d05280e5
4 changed files with 32 additions and 9 deletions

View file

@ -2232,14 +2232,18 @@ static Definition* CanonicalizeCommutativeDoubleArithmetic(Token::Kind op,
Definition* DoubleToFloatInstr::Canonicalize(FlowGraph* flow_graph) {
#ifdef DEBUG
// Must only be used in Float32 StoreIndexedInstr or FloatToDoubleInstr or
// Phis introduce by load forwarding.
// Must only be used in Float32 StoreIndexedInstr, FloatToDoubleInstr,
// Phis introduce by load forwarding, or MaterializeObject for
// eliminated Float32 array.
ASSERT(env_use_list() == NULL);
for (Value* use = input_use_list(); use != NULL; use = use->next_use()) {
ASSERT(use->instruction()->IsPhi() ||
use->instruction()->IsFloatToDouble() ||
(use->instruction()->IsStoreIndexed() &&
(use->instruction()->AsStoreIndexed()->class_id() ==
kTypedDataFloat32ArrayCid)) ||
(use->instruction()->IsMaterializeObject() &&
(use->instruction()->AsMaterializeObject()->cls().id() ==
kTypedDataFloat32ArrayCid)));
}
#endif

View file

@ -394,9 +394,16 @@ void DeferredObject::Fill() {
static_cast<uint64_t>(Integer::Cast(value).AsInt64Value()));
break;
case kTypedDataFloat32ArrayCid:
typed_data.SetFloat32(
element_offset,
static_cast<float>(Double::Cast(value).value()));
// Although element of Float32 array is represented with Double,
// it is already converted to 32-bit float via DoubleToFloat
// instruction before it was stored.
// Reinterpret double value as float to get the value back.
union {
double d;
float f;
} v;
v.d = Double::Cast(value).value();
typed_data.SetFloat32(element_offset, v.f);
break;
case kTypedDataFloat64ArrayCid:
typed_data.SetFloat64(element_offset,

View file

@ -66,9 +66,13 @@ String foo(double x, num doDeopt) {
Vector2 v2 = new Vector2(1.0, 2.0);
Vector2 v3 = v2 + Vector2(x, x);
double sum = v3.x + v3.y;
Float32List v4 = Float32List(2);
v4[0] = 11.0;
v4[1] = sum + 3;
print(v4[0]);
// Deoptimization is triggered here to materialize removed allocations.
doDeopt + 2;
return "v1: [${v1[0]},${v1[1]}], v2: [${v2.x},${v2.y}], v3: [${v3.x},${v3.y}], sum: $sum";
return "v1: [${v1[0]},${v1[1]}], v2: [${v2.x},${v2.y}], v3: [${v3.x},${v3.y}], v4: [${v4[0]}, ${v4[1]}], sum: $sum";
}
main() {
@ -80,6 +84,8 @@ main() {
for (int i = 0; i < 130; ++i) {
final num doDeopt = (i < 120 ? 1 : 2.0);
final result = foo(3.0, doDeopt);
Expect.equals("v1: [1,hi], v2: [1.0,2.0], v3: [4.0,5.0], sum: 9.0", result);
Expect.equals(
"v1: [1,hi], v2: [1.0,2.0], v3: [4.0,5.0], v4: [11.0, 12.0], sum: 9.0",
result);
}
}

View file

@ -66,9 +66,13 @@ String foo(double x, num doDeopt) {
Vector2 v2 = new Vector2(1.0, 2.0);
Vector2 v3 = v2 + Vector2(x, x);
double sum = v3.x + v3.y;
Float32List v4 = Float32List(2);
v4[0] = 11.0;
v4[1] = sum + 3;
print(v4[0]);
// Deoptimization is triggered here to materialize removed allocations.
doDeopt + 2;
return "v1: [${v1[0]},${v1[1]}], v2: [${v2.x},${v2.y}], v3: [${v3.x},${v3.y}], sum: $sum";
return "v1: [${v1[0]},${v1[1]}], v2: [${v2.x},${v2.y}], v3: [${v3.x},${v3.y}], v4: [${v4[0]}, ${v4[1]}], sum: $sum";
}
main() {
@ -80,6 +84,8 @@ main() {
for (int i = 0; i < 130; ++i) {
final num doDeopt = (i < 120 ? 1 : 2.0);
final result = foo(3.0, doDeopt);
Expect.equals("v1: [1,hi], v2: [1.0,2.0], v3: [4.0,5.0], sum: 9.0", result);
Expect.equals(
"v1: [1,hi], v2: [1.0,2.0], v3: [4.0,5.0], v4: [11.0, 12.0], sum: 9.0",
result);
}
}