Commit cf88badc authored by Théotime Grohens's avatar Théotime Grohens Committed by Commit Bot

[turbofan] Add remaining DataView getters in TurboFan.

This CL implements Reduction and Lowering for the DataView Int32,
Uint32, Float32 and Float64 getters.

This makes DataView getters fully supported in TurboFan (except for
BigInts), and should bridge the performance gap with TypedArrays.

Change-Id: Ifa98df9cf13e44d6468ad9ec8a19c86b41c6d2b1
Reviewed-on: https://chromium-review.googlesource.com/1127360
Commit-Queue: Théotime Grohens <theotime@google.com>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54288}
parent 00ff6b01
......@@ -3807,6 +3807,112 @@ Node* EffectControlLinearizer::LowerLoadDataViewElement(Node* node) {
return done.PhiAt(0);
}
case kExternalUint32Array: // Fall through.
case kExternalInt32Array: // Fall through.
case kExternalFloat32Array: {
Node* b0 = __ LoadElement(access_uint8, storage, index);
Node* b1 = __ LoadElement(access_uint8, storage,
__ Int32Add(index, __ Int32Constant(1)));
Node* b2 = __ LoadElement(access_uint8, storage,
__ Int32Add(index, __ Int32Constant(2)));
Node* b3 = __ LoadElement(access_uint8, storage,
__ Int32Add(index, __ Int32Constant(3)));
auto big_endian = __ MakeLabel();
auto done = __ MakeLabel(MachineRepresentation::kWord32);
__ GotoIfNot(is_little_endian, &big_endian);
{
// Little-endian load.
// result = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
Node* result =
__ Word32Or(__ Word32Or(__ Word32Shl(b3, __ Int32Constant(24)),
__ Word32Shl(b2, __ Int32Constant(16))),
__ Word32Or(__ Word32Shl(b1, __ Int32Constant(8)), b0));
__ Goto(&done, result);
}
__ Bind(&big_endian);
{
// Big-endian load.
// result = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
Node* result =
__ Word32Or(__ Word32Or(__ Word32Shl(b0, __ Int32Constant(24)),
__ Word32Shl(b1, __ Int32Constant(16))),
__ Word32Or(__ Word32Shl(b2, __ Int32Constant(8)), b3));
__ Goto(&done, result);
}
// We're done, return {result}.
__ Bind(&done);
if (element_type == kExternalFloat32Array) {
return __ BitcastInt32ToFloat32(done.PhiAt(0));
} else {
return done.PhiAt(0);
}
}
case kExternalFloat64Array: {
Node* b0 = __ LoadElement(access_uint8, storage, index);
Node* b1 = __ LoadElement(access_uint8, storage,
__ Int32Add(index, __ Int32Constant(1)));
Node* b2 = __ LoadElement(access_uint8, storage,
__ Int32Add(index, __ Int32Constant(2)));
Node* b3 = __ LoadElement(access_uint8, storage,
__ Int32Add(index, __ Int32Constant(3)));
Node* b4 = __ LoadElement(access_uint8, storage,
__ Int32Add(index, __ Int32Constant(4)));
Node* b5 = __ LoadElement(access_uint8, storage,
__ Int32Add(index, __ Int32Constant(5)));
Node* b6 = __ LoadElement(access_uint8, storage,
__ Int32Add(index, __ Int32Constant(6)));
Node* b7 = __ LoadElement(access_uint8, storage,
__ Int32Add(index, __ Int32Constant(7)));
auto big_endian = __ MakeLabel();
auto done = __ MakeLabel(MachineRepresentation::kWord32,
MachineRepresentation::kWord32);
__ GotoIfNot(is_little_endian, &big_endian);
{
// Little-endian load.
// low_word = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
// high_word = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4;
Node* low_word =
__ Word32Or(__ Word32Or(__ Word32Shl(b3, __ Int32Constant(24)),
__ Word32Shl(b2, __ Int32Constant(16))),
__ Word32Or(__ Word32Shl(b1, __ Int32Constant(8)), b0));
Node* high_word =
__ Word32Or(__ Word32Or(__ Word32Shl(b7, __ Int32Constant(24)),
__ Word32Shl(b6, __ Int32Constant(16))),
__ Word32Or(__ Word32Shl(b5, __ Int32Constant(8)), b4));
__ Goto(&done, low_word, high_word);
}
__ Bind(&big_endian);
{
// Big-endian load.
// high_word = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
// low_word = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
Node* high_word =
__ Word32Or(__ Word32Or(__ Word32Shl(b0, __ Int32Constant(24)),
__ Word32Shl(b1, __ Int32Constant(16))),
__ Word32Or(__ Word32Shl(b2, __ Int32Constant(8)), b3));
Node* low_word =
__ Word32Or(__ Word32Or(__ Word32Shl(b4, __ Int32Constant(24)),
__ Word32Shl(b5, __ Int32Constant(16))),
__ Word32Or(__ Word32Shl(b6, __ Int32Constant(8)), b7));
__ Goto(&done, low_word, high_word);
}
// We're done, store the low and high words into a float64.
__ Bind(&done);
Node* result = __ Float64Constant(0.0);
result = __ Float64InsertLowWord32(result, done.PhiAt(0));
result = __ Float64InsertHighWord32(result, done.PhiAt(1));
return result;
}
default:
UNREACHABLE();
}
......
......@@ -29,6 +29,7 @@ namespace compiler {
V(RoundFloat64ToInt32) \
V(TruncateFloat64ToWord32) \
V(Float64ExtractHighWord32) \
V(BitcastInt32ToFloat32) \
V(Float64Abs)
#define PURE_ASSEMBLER_MACH_BINOP_LIST(V) \
......@@ -60,6 +61,8 @@ namespace compiler {
V(Float64Equal) \
V(Float64LessThan) \
V(Float64LessThanOrEqual) \
V(Float64InsertLowWord32) \
V(Float64InsertHighWord32) \
V(Word32Equal) \
V(WordEqual)
......
......@@ -3440,6 +3440,18 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
case Builtins::kDataViewPrototypeGetInt16:
return ReduceDataViewPrototypeGet(node,
ExternalArrayType::kExternalInt16Array);
case Builtins::kDataViewPrototypeGetUint32:
return ReduceDataViewPrototypeGet(
node, ExternalArrayType::kExternalUint32Array);
case Builtins::kDataViewPrototypeGetInt32:
return ReduceDataViewPrototypeGet(node,
ExternalArrayType::kExternalInt32Array);
case Builtins::kDataViewPrototypeGetFloat32:
return ReduceDataViewPrototypeGet(
node, ExternalArrayType::kExternalFloat32Array);
case Builtins::kDataViewPrototypeGetFloat64:
return ReduceDataViewPrototypeGet(
node, ExternalArrayType::kExternalFloat64Array);
case Builtins::kTypedArrayPrototypeByteLength:
return ReduceArrayBufferViewAccessor(
node, JS_TYPED_ARRAY_TYPE,
......
......@@ -33,6 +33,26 @@ function readInt16Handled(offset, little_endian) {
}
}
function readUint32(offset, little_endian) {
return dataview.getUint32(offset, little_endian);
}
function readInt32Handled(offset, little_endian) {
try {
return dataview.getInt32(offset, little_endian);
} catch (e) {
return e;
}
}
function readFloat32(offset, little_endian) {
return dataview.getFloat32(offset, little_endian);
}
function readFloat64(offset, little_endian) {
return dataview.getFloat64(offset, little_endian);
}
function warmup(f) {
f(0);
f(1);
......@@ -69,11 +89,48 @@ assertEquals(0xabcd, readUint16(8));
assertEquals(0xcdab, readUint16(8, true));
// TurboFan valid getInt16.
dataview.setInt16(10, -0x1234);
let b1 = -0x1234;
dataview.setInt16(10, b1);
warmup(readInt16Handled);
assertEquals(-0x1234, readInt16Handled(10));
dataview.setInt16(10, -0x1234, true);
assertEquals(-0x1234, readInt16Handled(10, true));
assertOptimized(readInt16Handled);
assertEquals(b1, readInt16Handled(10));
dataview.setInt16(10, b1, true);
assertEquals(b1, readInt16Handled(10, true));
// TurboFan valid getUint32.
dataview.setUint32(12, 0xabcdef12);
warmup(readUint32);
assertOptimized(readUint32);
assertEquals(0xabcdef12, readUint32(12));
assertEquals(0x12efcdab, readUint32(12, true));
// TurboFan valid getInt32.
let b2 = -0x12345678;
dataview.setInt32(16, b2);
warmup(readInt32Handled);
assertOptimized(readInt32Handled);
assertEquals(b2, readInt32Handled(16));
dataview.setInt32(16, b2, true);
assertEquals(b2, readInt32Handled(16, true));
// TurboFan valid getFloat32.
let b3 = Math.fround(Math.E); // Round Math.E to float32.
dataview.setFloat32(16, b3);
warmup(readFloat32);
assertOptimized(readFloat32);
assertEquals(b3, readFloat32(16));
dataview.setFloat32(16, b3, true);
assertEquals(b3, readFloat32(16, true));
// TurboFan valid getFloat64.
let b4 = Math.PI;
dataview.setFloat64(16, b4);
warmup(readFloat64);
assertOptimized(readFloat64);
assertEquals(b4, readFloat64(16));
dataview.setFloat64(16, b4, true);
assertEquals(b4, readFloat64(16, true));
// TurboFan out of bounds read, throw with exception handler.
assertOptimized(readInt8Handled);
......@@ -82,11 +139,21 @@ assertOptimized(readInt8Handled);
assertOptimized(readInt16Handled);
assertInstanceof(readInt16Handled(23), RangeError);
assertOptimized(readInt16Handled);
assertOptimized(readInt32Handled);
assertInstanceof(readInt32Handled(21), RangeError);
assertOptimized(readInt32Handled);
// Without exception handler.
assertOptimized(readUint8);
assertThrows(() => readUint8(64));
assertThrows(() => readUint8(24));
assertOptimized(readUint8);
assertOptimized(readFloat32);
assertThrows(() => readFloat32(21));
assertOptimized(readFloat32);
assertOptimized(readFloat64);
assertThrows(() => readFloat64(17));
assertOptimized(readFloat64);
// TurboFan deoptimizations.
assertOptimized(readInt8Handled);
......@@ -101,7 +168,7 @@ assertUnoptimized(readInt8Handled);
// None of the stores wrote out of bounds.
var bytes = new Uint8Array(buffer);
for (var i = 0; i < 8; i++) assertEquals(0, bytes[i]);
for (var i = 24; i < 64; i++) assertEquals(0, bytes[i]);
for (var i = 32; i < 64; i++) assertEquals(0, bytes[i]);
// TurboFan neutered buffer.
warmup(readInt8Handled);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment