Commit 2bf048f4 authored by Benedikt Meurer's avatar Benedikt Meurer

[turbofan] Reduce context accesses during typed lowering.

TEST=unittests
R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/776243002

Cr-Commit-Position: refs/heads/master@{#25656}
parent 1364ea7c
......@@ -72,6 +72,15 @@ FieldAccess AccessBuilder::ForValue() {
}
// static
FieldAccess AccessBuilder::ForContextSlot(size_t index) {
int offset = Context::kHeaderSize + static_cast<int>(index) * kPointerSize;
DCHECK_EQ(offset,
Context::SlotOffset(static_cast<int>(index)) + kHeapObjectTag);
return {kTaggedBase, offset, Handle<Name>(), Type::Any(), kMachAnyTagged};
}
// static
ElementAccess AccessBuilder::ForFixedArrayElement() {
return {kTaggedBase, FixedArray::kHeaderSize, Type::Any(), kMachAnyTagged};
......
......@@ -43,6 +43,9 @@ class AccessBuilder FINAL : public AllStatic {
// Provides access to JSValue::value() field.
static FieldAccess ForValue();
// Provides access Context slots.
static FieldAccess ForContextSlot(size_t index);
// Provides access to FixedArray elements.
static ElementAccess ForFixedArrayElement();
......
......@@ -802,6 +802,47 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
}
Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
ContextAccess const& access = ContextAccessOf(node->op());
Node* const effect = NodeProperties::GetEffectInput(node);
Node* const control = graph()->start();
for (size_t i = 0; i < access.depth(); ++i) {
node->ReplaceInput(
0, graph()->NewNode(
simplified()->LoadField(
AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
NodeProperties::GetValueInput(node, 0), effect, control));
}
node->set_op(
simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
node->ReplaceInput(1, effect);
node->ReplaceInput(2, control);
DCHECK_EQ(3, node->InputCount());
return Changed(node);
}
Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
ContextAccess const& access = ContextAccessOf(node->op());
Node* const effect = NodeProperties::GetEffectInput(node);
Node* const control = graph()->start();
for (size_t i = 0; i < access.depth(); ++i) {
node->ReplaceInput(
0, graph()->NewNode(
simplified()->LoadField(
AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
NodeProperties::GetValueInput(node, 0), effect, control));
}
node->set_op(
simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
node->RemoveInput(2);
DCHECK_EQ(4, node->InputCount());
return Changed(node);
}
static Reduction ReplaceWithReduction(Node* node, Reduction reduction) {
if (reduction.Changed()) {
NodeProperties::ReplaceWithValue(node, reduction.replacement());
......@@ -888,6 +929,10 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSLoadProperty(node);
case IrOpcode::kJSStoreProperty:
return ReduceJSStoreProperty(node);
case IrOpcode::kJSLoadContext:
return ReduceJSLoadContext(node);
case IrOpcode::kJSStoreContext:
return ReduceJSStoreContext(node);
case IrOpcode::kJSCallFunction:
return JSBuiltinReducer(jsgraph()).Reduce(node);
default:
......
......@@ -38,6 +38,8 @@ class JSTypedLowering FINAL : public Reducer {
Reduction ReduceJSComparison(Node* node);
Reduction ReduceJSLoadProperty(Node* node);
Reduction ReduceJSStoreProperty(Node* node);
Reduction ReduceJSLoadContext(Node* node);
Reduction ReduceJSStoreContext(Node* node);
Reduction ReduceJSEqual(Node* node, bool invert);
Reduction ReduceJSStrictEqual(Node* node, bool invert);
Reduction ReduceJSToNumberInput(Node* input);
......
......@@ -25,6 +25,9 @@ const ExternalArrayType kExternalArrayTypes[] = {
kExternalFloat32Array, kExternalFloat64Array};
const size_t kIndices[] = {0, 1, 42, 100, 1024};
Type* const kJSTypes[] = {Type::Undefined(), Type::Null(), Type::Boolean(),
Type::Number(), Type::String(), Type::Object()};
......@@ -229,6 +232,74 @@ TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndUnsigned32) {
}
// -----------------------------------------------------------------------------
// JSLoadContext
TEST_F(JSTypedLoweringTest, JSLoadContext) {
Node* const context = Parameter(Type::Any());
Node* const effect = graph()->start();
static bool kBooleans[] = {false, true};
TRACED_FOREACH(size_t, index, kIndices) {
TRACED_FOREACH(bool, immutable, kBooleans) {
Reduction const r1 = Reduce(
graph()->NewNode(javascript()->LoadContext(0, index, immutable),
context, context, effect));
ASSERT_TRUE(r1.Changed());
EXPECT_THAT(r1.replacement(),
IsLoadField(AccessBuilder::ForContextSlot(index), context,
effect, graph()->start()));
Reduction const r2 = Reduce(
graph()->NewNode(javascript()->LoadContext(1, index, immutable),
context, context, effect));
ASSERT_TRUE(r2.Changed());
EXPECT_THAT(r2.replacement(),
IsLoadField(AccessBuilder::ForContextSlot(index),
IsLoadField(AccessBuilder::ForContextSlot(
Context::PREVIOUS_INDEX),
context, effect, graph()->start()),
effect, graph()->start()));
}
}
}
// -----------------------------------------------------------------------------
// JSStoreContext
TEST_F(JSTypedLoweringTest, JSStoreContext) {
Node* const context = Parameter(Type::Any());
Node* const effect = graph()->start();
Node* const control = graph()->start();
TRACED_FOREACH(size_t, index, kIndices) {
TRACED_FOREACH(Type*, type, kJSTypes) {
Node* const value = Parameter(type);
Reduction const r1 =
Reduce(graph()->NewNode(javascript()->StoreContext(0, index), context,
value, context, effect, control));
ASSERT_TRUE(r1.Changed());
EXPECT_THAT(r1.replacement(),
IsStoreField(AccessBuilder::ForContextSlot(index), context,
value, effect, control));
Reduction const r2 =
Reduce(graph()->NewNode(javascript()->StoreContext(1, index), context,
value, context, effect, control));
ASSERT_TRUE(r2.Changed());
EXPECT_THAT(r2.replacement(),
IsStoreField(AccessBuilder::ForContextSlot(index),
IsLoadField(AccessBuilder::ForContextSlot(
Context::PREVIOUS_INDEX),
context, effect, graph()->start()),
value, effect, control));
}
}
}
// -----------------------------------------------------------------------------
// JSLoadProperty
......
......@@ -533,6 +533,59 @@ class IsLoadFieldMatcher FINAL : public NodeMatcher {
};
class IsStoreFieldMatcher FINAL : public NodeMatcher {
public:
IsStoreFieldMatcher(const Matcher<FieldAccess>& access_matcher,
const Matcher<Node*>& base_matcher,
const Matcher<Node*>& value_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher)
: NodeMatcher(IrOpcode::kStoreField),
access_matcher_(access_matcher),
base_matcher_(base_matcher),
value_matcher_(value_matcher),
effect_matcher_(effect_matcher),
control_matcher_(control_matcher) {}
virtual void DescribeTo(std::ostream* os) const OVERRIDE {
NodeMatcher::DescribeTo(os);
*os << " whose access (";
access_matcher_.DescribeTo(os);
*os << "), base (";
base_matcher_.DescribeTo(os);
*os << "), value (";
value_matcher_.DescribeTo(os);
*os << "), effect (";
effect_matcher_.DescribeTo(os);
*os << ") and control (";
control_matcher_.DescribeTo(os);
*os << ")";
}
virtual bool MatchAndExplain(Node* node,
MatchResultListener* listener) const OVERRIDE {
return (NodeMatcher::MatchAndExplain(node, listener) &&
PrintMatchAndExplain(OpParameter<FieldAccess>(node), "access",
access_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
base_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
"value", value_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
effect_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetControlInput(node),
"control", control_matcher_, listener));
}
private:
const Matcher<FieldAccess> access_matcher_;
const Matcher<Node*> base_matcher_;
const Matcher<Node*> value_matcher_;
const Matcher<Node*> effect_matcher_;
const Matcher<Node*> control_matcher_;
};
class IsLoadBufferMatcher FINAL : public NodeMatcher {
public:
IsLoadBufferMatcher(const Matcher<BufferAccess>& access_matcher,
......@@ -1132,6 +1185,17 @@ Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher,
}
Matcher<Node*> IsStoreField(const Matcher<FieldAccess>& access_matcher,
const Matcher<Node*>& base_matcher,
const Matcher<Node*>& value_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher) {
return MakeMatcher(new IsStoreFieldMatcher(access_matcher, base_matcher,
value_matcher, effect_matcher,
control_matcher));
}
Matcher<Node*> IsLoadBuffer(const Matcher<BufferAccess>& access_matcher,
const Matcher<Node*>& buffer_matcher,
const Matcher<Node*>& offset_matcher,
......
......@@ -88,6 +88,11 @@ Matcher<Node*> IsLoadField(const Matcher<FieldAccess>& access_matcher,
const Matcher<Node*>& base_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsStoreField(const Matcher<FieldAccess>& access_matcher,
const Matcher<Node*>& base_matcher,
const Matcher<Node*>& value_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsLoadBuffer(const Matcher<BufferAccess>& access_matcher,
const Matcher<Node*>& buffer_matcher,
const Matcher<Node*>& offset_matcher,
......
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