From: mstarzinger@chromium.org Date: Thu, 28 Aug 2014 14:35:11 +0000 (+0000) Subject: Preliminary lowering of typed array loads in TF. X-Git-Tag: upstream/4.7.83~7299 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=cc8cec354ce674796293046f90d03ebaac65813b;p=platform%2Fupstream%2Fv8.git Preliminary lowering of typed array loads in TF. R=titzer@chromium.org TEST=cctest/test-run-properties/TypedArrayLoad Review URL: https://codereview.chromium.org/516853002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23492 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/BUILD.gn b/BUILD.gn index 26c9946..46aaaec 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -460,6 +460,7 @@ source_set("v8_base") { "src/codegen.h", "src/compilation-cache.cc", "src/compilation-cache.h", + "src/compiler/access-builder.h", "src/compiler/ast-graph-builder.cc", "src/compiler/ast-graph-builder.h", "src/compiler/change-lowering.cc", diff --git a/src/compiler.cc b/src/compiler.cc index 0b75c89..b46a201 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -139,6 +139,7 @@ void CompilationInfo::Initialize(Isolate* isolate, if (script_->type()->value() == Script::TYPE_NATIVE) MarkAsNative(); if (isolate_->debug()->is_active()) MarkAsDebug(); if (FLAG_context_specialization) MarkAsContextSpecializing(); + if (FLAG_turbo_types) MarkAsTypingEnabled(); if (!shared_info_.is_null()) { DCHECK(strict_mode() == SLOPPY); diff --git a/src/compiler.h b/src/compiler.h index 82c0b87..00cd0f4 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -81,7 +81,8 @@ class CompilationInfo { kParseRestriction = 1 << 14, kSerializing = 1 << 15, kContextSpecializing = 1 << 16, - kInliningEnabled = 1 << 17 + kInliningEnabled = 1 << 17, + kTypingEnabled = 1 << 18 }; CompilationInfo(Handle closure, Zone* zone); @@ -191,6 +192,10 @@ class CompilationInfo { bool is_inlining_enabled() const { return GetFlag(kInliningEnabled); } + void MarkAsTypingEnabled() { SetFlag(kTypingEnabled); } + + bool is_typing_enabled() const { return GetFlag(kTypingEnabled); } + bool IsCodePreAgingActive() const { return FLAG_optimize_for_size && FLAG_age_code && !will_serialize() && !is_debug(); diff --git a/src/compiler/access-builder.h b/src/compiler/access-builder.h new file mode 100644 index 0000000..a22df9d --- /dev/null +++ b/src/compiler/access-builder.h @@ -0,0 +1,67 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_COMPILER_ACCESS_BUILDER_H_ +#define V8_COMPILER_ACCESS_BUILDER_H_ + +#include "src/compiler/simplified-operator.h" + +namespace v8 { +namespace internal { +namespace compiler { + +// This access builder provides a set of static methods constructing commonly +// used FieldAccess and ElementAccess descriptors. These descriptors server as +// parameters to simplified load/store operators. +class AccessBuilder : public AllStatic { + public: + // Provides access to JSObject::elements() field. + static FieldAccess ForJSObjectElements() { + return {kTaggedBase, JSObject::kElementsOffset, Handle(), + Type::Internal(), kMachAnyTagged}; + } + + // Provides access to ExternalArray::external_pointer() field. + static FieldAccess ForExternalArrayPointer() { + return {kTaggedBase, ExternalArray::kExternalPointerOffset, Handle(), + Type::UntaggedPtr(), kMachPtr}; + } + + // Provides access to Fixed{type}TypedArray and External{type}Array elements. + static ElementAccess ForTypedArrayElement(ExternalArrayType type, + bool is_external) { + BaseTaggedness taggedness = is_external ? kUntaggedBase : kTaggedBase; + int header_size = is_external ? 0 : FixedTypedArrayBase::kDataOffset; + switch (type) { + case kExternalInt8Array: + return {taggedness, header_size, Type::Signed32(), kMachInt8}; + case kExternalUint8Array: + case kExternalUint8ClampedArray: + return {taggedness, header_size, Type::Unsigned32(), kMachUint8}; + case kExternalInt16Array: + return {taggedness, header_size, Type::Signed32(), kMachInt16}; + case kExternalUint16Array: + return {taggedness, header_size, Type::Unsigned32(), kMachUint16}; + case kExternalInt32Array: + return {taggedness, header_size, Type::Signed32(), kMachInt32}; + case kExternalUint32Array: + return {taggedness, header_size, Type::Unsigned32(), kMachUint32}; + case kExternalFloat32Array: + return {taggedness, header_size, Type::Number(), kRepFloat32}; + case kExternalFloat64Array: + return {taggedness, header_size, Type::Number(), kRepFloat64}; + } + UNREACHABLE(); + return {kUntaggedBase, 0, Type::None(), kMachNone}; + } + + private: + DISALLOW_COPY_AND_ASSIGN(AccessBuilder); +}; + +} // namespace compiler +} // namespace internal +} // namespace v8 + +#endif // V8_COMPILER_ACCESS_BUILDER_H_ diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc index 4c166e0..64663df 100644 --- a/src/compiler/js-typed-lowering.cc +++ b/src/compiler/js-typed-lowering.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/compiler/access-builder.h" #include "src/compiler/graph-inl.h" #include "src/compiler/js-typed-lowering.h" #include "src/compiler/node-aux-data-inl.h" @@ -499,6 +500,43 @@ Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) { } +Reduction JSTypedLowering::ReduceJSPropertyLoad(Node* node) { + Node* key = NodeProperties::GetValueInput(node, 1); + Node* base = NodeProperties::GetValueInput(node, 0); + Type* key_type = NodeProperties::GetBounds(key).upper; + Type* base_type = NodeProperties::GetBounds(base).upper; + // TODO(mstarzinger): This lowering is not correct if: + // a) The typed array turns external (i.e. MaterializeArrayBuffer) + // b) The typed array or it's buffer is neutered. + // c) The index is out of bounds. + if (base_type->IsConstant() && key_type->Is(Type::Integral32()) && + base_type->AsConstant()->Value()->IsJSTypedArray()) { + // JSLoadProperty(typed-array, int32) + JSTypedArray* array = JSTypedArray::cast(*base_type->AsConstant()->Value()); + ElementsKind elements_kind = array->map()->elements_kind(); + ExternalArrayType type = array->type(); + ElementAccess element_access; + Node* elements = graph()->NewNode( + simplified()->LoadField(AccessBuilder::ForJSObjectElements()), base, + NodeProperties::GetEffectInput(node)); + if (IsExternalArrayElementsKind(elements_kind)) { + elements = graph()->NewNode( + simplified()->LoadField(AccessBuilder::ForExternalArrayPointer()), + elements, NodeProperties::GetEffectInput(node)); + element_access = AccessBuilder::ForTypedArrayElement(type, true); + } else { + DCHECK(IsFixedTypedArrayElementsKind(elements_kind)); + element_access = AccessBuilder::ForTypedArrayElement(type, false); + } + Node* value = + graph()->NewNode(simplified()->LoadElement(element_access), elements, + key, NodeProperties::GetEffectInput(node)); + return ReplaceEagerly(node, value); + } + return NoChange(); +} + + static Reduction ReplaceWithReduction(Node* node, Reduction reduction) { if (reduction.Changed()) { NodeProperties::ReplaceWithValue(node, reduction.replacement()); @@ -573,6 +611,8 @@ Reduction JSTypedLowering::Reduce(Node* node) { case IrOpcode::kJSToString: return ReplaceWithReduction(node, ReduceJSToStringInput(node->InputAt(0))); + case IrOpcode::kJSLoadProperty: + return ReduceJSPropertyLoad(node); default: break; } diff --git a/src/compiler/js-typed-lowering.h b/src/compiler/js-typed-lowering.h index 98888df..3e98b79 100644 --- a/src/compiler/js-typed-lowering.h +++ b/src/compiler/js-typed-lowering.h @@ -39,6 +39,7 @@ class JSTypedLowering : public Reducer { Reduction ReplaceWith(Node* node) { return Reducer::Replace(node); } Reduction ReduceJSAdd(Node* node); Reduction ReduceJSComparison(Node* node); + Reduction ReduceJSPropertyLoad(Node* node); Reduction ReduceJSEqual(Node* node, bool invert); Reduction ReduceJSStrictEqual(Node* node, bool invert); Reduction ReduceJSToNumberInput(Node* input); diff --git a/src/compiler/pipeline.cc b/src/compiler/pipeline.cc index 250999c..1daf417 100644 --- a/src/compiler/pipeline.cc +++ b/src/compiler/pipeline.cc @@ -16,11 +16,13 @@ #include "src/compiler/js-generic-lowering.h" #include "src/compiler/js-inlining.h" #include "src/compiler/js-typed-lowering.h" +#include "src/compiler/machine-operator-reducer.h" #include "src/compiler/phi-reducer.h" #include "src/compiler/register-allocator.h" #include "src/compiler/schedule.h" #include "src/compiler/scheduler.h" #include "src/compiler/simplified-lowering.h" +#include "src/compiler/simplified-operator-reducer.h" #include "src/compiler/typer.h" #include "src/compiler/verifier.h" #include "src/hydrogen.h" @@ -213,7 +215,7 @@ Handle Pipeline::GenerateCode() { GraphReplayPrinter::PrintReplay(&graph); } - if (FLAG_turbo_types) { + if (info()->is_typing_enabled()) { { // Type the graph. PhaseStats typer_stats(info(), PhaseStats::CREATE_GRAPH, "typer"); @@ -247,15 +249,20 @@ Handle Pipeline::GenerateCode() { } { // Lower changes that have been inserted before. - PhaseStats lowering_stats(info(), PhaseStats::CREATE_GRAPH, + PhaseStats lowering_stats(info(), PhaseStats::OPTIMIZATION, "change lowering"); SourcePositionTable::Scope pos(&source_positions, SourcePosition::Unknown()); Linkage linkage(info()); MachineOperatorBuilder machine(zone()); + SimplifiedOperatorReducer simple_reducer(&jsgraph, &machine); ChangeLowering lowering(&jsgraph, &linkage, &machine); + MachineOperatorReducer mach_reducer(&graph); GraphReducer graph_reducer(&graph); + // TODO(titzer): Figure out if we should run all reducers at once here. + graph_reducer.AddReducer(&simple_reducer); graph_reducer.AddReducer(&lowering); + graph_reducer.AddReducer(&mach_reducer); graph_reducer.ReduceGraph(); VerifyAndPrintGraph(&graph, "Lowered changes"); diff --git a/src/compiler/simplified-operator.h b/src/compiler/simplified-operator.h index a048b62..c2ca942 100644 --- a/src/compiler/simplified-operator.h +++ b/src/compiler/simplified-operator.h @@ -94,6 +94,55 @@ inline const ElementAccess ElementAccessOf(Operator* op) { } +// This access helper provides a set of static methods constructing commonly +// used FieldAccess and ElementAccess descriptors. +class Access : public AllStatic { + public: + // Provides access to JSObject::elements() field. + static FieldAccess ForJSObjectElements() { + return {kTaggedBase, JSObject::kElementsOffset, Handle(), + Type::Internal(), kMachAnyTagged}; + } + + // Provides access to ExternalArray::external_pointer() field. + static FieldAccess ForExternalArrayPointer() { + return {kTaggedBase, ExternalArray::kExternalPointerOffset, Handle(), + Type::UntaggedPtr(), kMachPtr}; + } + + // Provides access to Fixed{type}TypedArray and External{type}Array elements. + static ElementAccess ForTypedArrayElement(ExternalArrayType type, + bool is_external) { + BaseTaggedness taggedness = is_external ? kUntaggedBase : kTaggedBase; + int header_size = is_external ? 0 : FixedTypedArrayBase::kDataOffset; + switch (type) { + case kExternalInt8Array: + return {taggedness, header_size, Type::Signed32(), kMachInt8}; + case kExternalUint8Array: + case kExternalUint8ClampedArray: + return {taggedness, header_size, Type::Unsigned32(), kMachUint8}; + case kExternalInt16Array: + return {taggedness, header_size, Type::Signed32(), kMachInt16}; + case kExternalUint16Array: + return {taggedness, header_size, Type::Unsigned32(), kMachUint16}; + case kExternalInt32Array: + return {taggedness, header_size, Type::Signed32(), kMachInt32}; + case kExternalUint32Array: + return {taggedness, header_size, Type::Unsigned32(), kMachUint32}; + case kExternalFloat32Array: + return {taggedness, header_size, Type::Number(), kRepFloat32}; + case kExternalFloat64Array: + return {taggedness, header_size, Type::Number(), kRepFloat64}; + } + UNREACHABLE(); + return {kUntaggedBase, 0, Type::None(), kMachNone}; + } + + private: + DISALLOW_COPY_AND_ASSIGN(Access); +}; + + // Interface for building simplified operators, which represent the // medium-level operations of V8, including adding numbers, allocating objects, // indexing into objects and arrays, etc. diff --git a/src/objects-printer.cc b/src/objects-printer.cc index 617a8f2..ca7ee23 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -751,7 +751,7 @@ void JSArrayBuffer::JSArrayBufferPrint(OStream& os) { // NOLINT void JSTypedArray::JSTypedArrayPrint(OStream& os) { // NOLINT HeapObject::PrintHeader(os, "JSTypedArray"); os << " - map = " << reinterpret_cast(map()) << "\n"; - os << " - buffer =" << Brief(buffer()); + os << " - buffer = " << Brief(buffer()); os << "\n - byte_offset = " << Brief(byte_offset()); os << "\n - byte_length = " << Brief(byte_length()); os << "\n - length = " << Brief(length()); diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp index aad95da..bec1a4c 100644 --- a/test/cctest/cctest.gyp +++ b/test/cctest/cctest.gyp @@ -79,6 +79,7 @@ 'compiler/test-run-jsexceptions.cc', 'compiler/test-run-jsops.cc', 'compiler/test-run-machops.cc', + 'compiler/test-run-properties.cc', 'compiler/test-run-variables.cc', 'compiler/test-schedule.cc', 'compiler/test-scheduler.cc', diff --git a/test/cctest/compiler/function-tester.h b/test/cctest/compiler/function-tester.h index afed296..1386b36 100644 --- a/test/cctest/compiler/function-tester.h +++ b/test/cctest/compiler/function-tester.h @@ -32,7 +32,8 @@ class FunctionTester : public InitializedHandleScope { flags_(flags) { Compile(function); const uint32_t supported_flags = CompilationInfo::kContextSpecializing | - CompilationInfo::kInliningEnabled; + CompilationInfo::kInliningEnabled | + CompilationInfo::kTypingEnabled; CHECK_EQ(0, flags_ & ~supported_flags); } @@ -53,6 +54,9 @@ class FunctionTester : public InitializedHandleScope { if (flags_ & CompilationInfo::kInliningEnabled) { info.MarkAsInliningEnabled(); } + if (flags_ & CompilationInfo::kTypingEnabled) { + info.MarkAsTypingEnabled(); + } CHECK(Rewriter::Rewrite(&info)); CHECK(Scope::Analyze(&info)); CHECK_NE(NULL, info.scope()); diff --git a/test/cctest/compiler/test-run-properties.cc b/test/cctest/compiler/test-run-properties.cc new file mode 100644 index 0000000..c6d8dc8 --- /dev/null +++ b/test/cctest/compiler/test-run-properties.cc @@ -0,0 +1,70 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/v8.h" + +#include "test/cctest/compiler/function-tester.h" + +using namespace v8::internal; +using namespace v8::internal::compiler; + +template +static void TypedArrayLoadHelper(const char* array_type) { + const int64_t values[] = { + 0x00000000, 0x00000001, 0x00000023, 0x00000042, 0x12345678, 0x87654321, + 0x0000003f, 0x0000007f, 0x00003fff, 0x00007fff, 0x3fffffff, 0x7fffffff, + 0x000000ff, 0x00000080, 0x0000ffff, 0x00008000, 0xffffffff, 0x80000000, + }; + size_t size = arraysize(values); + EmbeddedVector values_buffer; + StringBuilder values_builder(values_buffer.start(), values_buffer.length()); + for (unsigned i = 0; i < size; i++) { + values_builder.AddFormatted("a[%d] = 0x%08x;", i, values[i]); + } + + // Note that below source creates two different typed arrays with distinct + // elements kind to get coverage for both access patterns: + // - IsFixedTypedArrayElementsKind(x) + // - IsExternalArrayElementsKind(y) + const char* source = + "(function(a) {" + " var x = (a = new %1$sArray(%2$d)); %3$s;" + " var y = (a = new %1$sArray(%2$d)); %3$s; %%TypedArrayGetBuffer(y);" + " if (!%%HasFixed%1$sElements(x)) %%AbortJS('x');" + " if (!%%HasExternal%1$sElements(y)) %%AbortJS('y');" + " function f(a,b) {" + " a = a | 0; b = b | 0;" + " return x[a] + y[b];" + " }" + " return f;" + "})()"; + EmbeddedVector source_buffer; + SNPrintF(source_buffer, source, array_type, size, values_buffer.start()); + + FunctionTester T( + source_buffer.start(), + CompilationInfo::kContextSpecializing | CompilationInfo::kTypingEnabled); + for (unsigned i = 0; i < size; i++) { + for (unsigned j = 0; j < size; j++) { + double value_a = static_cast(values[i]); + double value_b = static_cast(values[j]); + double expected = value_a + value_b; + T.CheckCall(T.Val(expected), T.Val(i), T.Val(j)); + } + } +} + + +TEST(TypedArrayLoad) { + FLAG_typed_array_max_size_in_heap = 256; + TypedArrayLoadHelper("Int8"); + TypedArrayLoadHelper("Uint8"); + TypedArrayLoadHelper("Int16"); + TypedArrayLoadHelper("Uint16"); + TypedArrayLoadHelper("Int32"); + TypedArrayLoadHelper("Uint32"); + TypedArrayLoadHelper("Float64"); + // TODO(mstarzinger): Add tests for Float32. + // TODO(mstarzinger): Add tests for ClampedUint8. +} diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index a6f7d28..bdb487a 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -342,6 +342,7 @@ '../../src/codegen.h', '../../src/compilation-cache.cc', '../../src/compilation-cache.h', + '../../src/compiler/access-builder.h', '../../src/compiler/ast-graph-builder.cc', '../../src/compiler/ast-graph-builder.h', '../../src/compiler/change-lowering.cc',