Preliminary lowering of typed array loads in TF.
authormstarzinger@chromium.org <mstarzinger@chromium.org>
Thu, 28 Aug 2014 14:35:11 +0000 (14:35 +0000)
committermstarzinger@chromium.org <mstarzinger@chromium.org>
Thu, 28 Aug 2014 14:35:11 +0000 (14:35 +0000)
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

13 files changed:
BUILD.gn
src/compiler.cc
src/compiler.h
src/compiler/access-builder.h [new file with mode: 0644]
src/compiler/js-typed-lowering.cc
src/compiler/js-typed-lowering.h
src/compiler/pipeline.cc
src/compiler/simplified-operator.h
src/objects-printer.cc
test/cctest/cctest.gyp
test/cctest/compiler/function-tester.h
test/cctest/compiler/test-run-properties.cc [new file with mode: 0644]
tools/gyp/v8.gyp

index 26c9946..46aaaec 100644 (file)
--- 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",
index 0b75c89..b46a201 100644 (file)
@@ -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);
index 82c0b87..00cd0f4 100644 (file)
@@ -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<JSFunction> 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 (file)
index 0000000..a22df9d
--- /dev/null
@@ -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<Name>(),
+            Type::Internal(), kMachAnyTagged};
+  }
+
+  // Provides access to ExternalArray::external_pointer() field.
+  static FieldAccess ForExternalArrayPointer() {
+    return {kTaggedBase, ExternalArray::kExternalPointerOffset, Handle<Name>(),
+            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_
index 4c166e0..64663df 100644 (file)
@@ -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;
   }
index 98888df..3e98b79 100644 (file)
@@ -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);
index 250999c..1daf417 100644 (file)
 #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<Code> 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<Code> 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");
index a048b62..c2ca942 100644 (file)
@@ -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<Name>(),
+            Type::Internal(), kMachAnyTagged};
+  }
+
+  // Provides access to ExternalArray::external_pointer() field.
+  static FieldAccess ForExternalArrayPointer() {
+    return {kTaggedBase, ExternalArray::kExternalPointerOffset, Handle<Name>(),
+            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.
index 617a8f2..ca7ee23 100644 (file)
@@ -751,7 +751,7 @@ void JSArrayBuffer::JSArrayBufferPrint(OStream& os) {  // NOLINT
 void JSTypedArray::JSTypedArrayPrint(OStream& os) {  // NOLINT
   HeapObject::PrintHeader(os, "JSTypedArray");
   os << " - map = " << reinterpret_cast<void*>(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());
index aad95da..bec1a4c 100644 (file)
@@ -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',
index afed296..1386b36 100644 (file)
@@ -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 (file)
index 0000000..c6d8dc8
--- /dev/null
@@ -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 <typename U>
+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<char, 1024> 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<char, 1024> 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<U>(values[i]);
+      double value_b = static_cast<U>(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_t>("Int8");
+  TypedArrayLoadHelper<uint8_t>("Uint8");
+  TypedArrayLoadHelper<int16_t>("Int16");
+  TypedArrayLoadHelper<uint16_t>("Uint16");
+  TypedArrayLoadHelper<int32_t>("Int32");
+  TypedArrayLoadHelper<uint32_t>("Uint32");
+  TypedArrayLoadHelper<double>("Float64");
+  // TODO(mstarzinger): Add tests for Float32.
+  // TODO(mstarzinger): Add tests for ClampedUint8.
+}
index a6f7d28..bdb487a 100644 (file)
         '../../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',