Commit ea891e87 authored by Jaroslav Sevcik's avatar Jaroslav Sevcik Committed by Commit Bot

[turbofan] Load elimination - use maps to avoid state invalidation.

Currently, the transition elements kind operation invalidates the
elements of all other arrays. In particular, if we loop over matrix 
elements using two nested loops, and do possibly transitioning access 
a[i][j] in every iteration, we invalidate the load elimination state 
for the array 'a' because a[i][j] might transition elements kind 
for the 'a[i]' array. As a result, the 'a[i]' access cannot be 
hoisted from the inner loop.

With this CL, we figure out that transitioning 'a[i]' cannot affect 'a'
because we know that 'a' does not have the transition's source map.

In the micro-benchmark below, the time for summing up the elements of
100x100 matrix improves by factor of 1.7 (from ~340ms to ~190ms).

function matrixSum(a) {
  let s = 0;
  let rowCount = a.length;
  let columnCount = a[0].length;
  for (let i = 0; i < rowCount; i++) {
    for (let j = 0; j < columnCount ; j++) {
      s += a[i][j];
    }
  }
  return s;
}

// Setup the matrices:
// Smi elements.
var ma = [[1, 2], [3, 4]];
// Holey double elements.
var b = Array(100);
for (let i = 0; i < 100; i++) b[i] = 1.1;
var mb = [];
for (let i = 0; i < 100; i++) mb[i] = b;

// Warmup.
matrixSum(mb);
matrixSum(mb);
matrixSum(ma);
matrixSum(mb);
matrixSum(ma);

%OptimizeFunctionOnNextCall(matrixSum);

function runner(m) {
  let s = 0;
  for (let i = 0; i < 1e4; i++) {
    s += matrixSum(m);
  }
  return s;
}
// Make sure the runner does not know the elements kinds.
%NeverOptimizeFunction(runner);

// Measure.
console.time("Sum");
runner(mb);
console.timeEnd("Sum");


Bug: v8:6344
Change-Id: Ie0642d8693ed63116b1aaed7d2f261fcb64729fe
Reviewed-on: https://chromium-review.googlesource.com/704634
Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48334}
parent afbfddd7
This diff is collapsed.
...@@ -125,6 +125,11 @@ class V8_EXPORT_PRIVATE LoadElimination final ...@@ -125,6 +125,11 @@ class V8_EXPORT_PRIVATE LoadElimination final
size_t next_index_ = 0; size_t next_index_ = 0;
}; };
// Information we use to resolve object aliasing. Currently, we consider
// object not aliased if they have different maps or if the nodes may
// not alias.
class AliasStateInfo;
// Abstract state to approximate the current state of a certain field along // Abstract state to approximate the current state of a certain field along
// the effect paths through the graph. // the effect paths through the graph.
class AbstractField final : public ZoneObject { class AbstractField final : public ZoneObject {
...@@ -143,8 +148,8 @@ class V8_EXPORT_PRIVATE LoadElimination final ...@@ -143,8 +148,8 @@ class V8_EXPORT_PRIVATE LoadElimination final
return that; return that;
} }
Node* Lookup(Node* object) const; Node* Lookup(Node* object) const;
AbstractField const* Kill(Node* object, MaybeHandle<Name> name, AbstractField const* Kill(const AliasStateInfo& alias_info,
Zone* zone) const; MaybeHandle<Name> name, Zone* zone) const;
bool Equals(AbstractField const* that) const { bool Equals(AbstractField const* that) const {
return this == that || this->info_for_node_ == that->info_for_node_; return this == that || this->info_for_node_ == that->info_for_node_;
} }
...@@ -196,7 +201,8 @@ class V8_EXPORT_PRIVATE LoadElimination final ...@@ -196,7 +201,8 @@ class V8_EXPORT_PRIVATE LoadElimination final
AbstractMaps const* Extend(Node* object, ZoneHandleSet<Map> maps, AbstractMaps const* Extend(Node* object, ZoneHandleSet<Map> maps,
Zone* zone) const; Zone* zone) const;
bool Lookup(Node* object, ZoneHandleSet<Map>* object_maps) const; bool Lookup(Node* object, ZoneHandleSet<Map>* object_maps) const;
AbstractMaps const* Kill(Node* object, Zone* zone) const; AbstractMaps const* Kill(const AliasStateInfo& alias_info,
Zone* zone) const;
bool Equals(AbstractMaps const* that) const { bool Equals(AbstractMaps const* that) const {
return this == that || this->info_for_node_ == that->info_for_node_; return this == that || this->info_for_node_ == that->info_for_node_;
} }
...@@ -222,10 +228,15 @@ class V8_EXPORT_PRIVATE LoadElimination final ...@@ -222,10 +228,15 @@ class V8_EXPORT_PRIVATE LoadElimination final
AbstractState const* AddMaps(Node* object, ZoneHandleSet<Map> maps, AbstractState const* AddMaps(Node* object, ZoneHandleSet<Map> maps,
Zone* zone) const; Zone* zone) const;
AbstractState const* KillMaps(Node* object, Zone* zone) const; AbstractState const* KillMaps(Node* object, Zone* zone) const;
AbstractState const* KillMaps(const AliasStateInfo& alias_info,
Zone* zone) const;
bool LookupMaps(Node* object, ZoneHandleSet<Map>* object_maps) const; bool LookupMaps(Node* object, ZoneHandleSet<Map>* object_maps) const;
AbstractState const* AddField(Node* object, size_t index, Node* value, AbstractState const* AddField(Node* object, size_t index, Node* value,
MaybeHandle<Name> name, Zone* zone) const; MaybeHandle<Name> name, Zone* zone) const;
AbstractState const* KillField(const AliasStateInfo& alias_info,
size_t index, MaybeHandle<Name> name,
Zone* zone) const;
AbstractState const* KillField(Node* object, size_t index, AbstractState const* KillField(Node* object, size_t index,
MaybeHandle<Name> name, Zone* zone) const; MaybeHandle<Name> name, Zone* zone) const;
AbstractState const* KillFields(Node* object, MaybeHandle<Name> name, AbstractState const* KillFields(Node* object, MaybeHandle<Name> name,
......
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