d1b5aa0716
A CompilationInfo constructed from just an Isolate* and a Zone* is in weird an inconsistent state (calling e.g. flags() on it will crash), so we need to avoid them. This CL removes almost all of them, the remaining 2 call sites in (for testing only) will be handled in a separate CL. Things which have been changed: * Linkage is basically a decorator for CallDescriptor now. * ChangeLowering doesn't need Linkage at all. * JSGenericLowering doesn't need a full CompilationInfo*, just a single flag. * JSContextSpecializer doesn't need the full CompilationInfo, just a Context. * Removed unused CompilationInfo from SimplifiedLoweringTester. This nicely decouples things already a bit more, but there's still work to do... Review URL: https://codereview.chromium.org/899803003 Cr-Commit-Position: refs/heads/master@{#26580}
462 lines
16 KiB
C++
462 lines
16 KiB
C++
// 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/code-stubs.h"
|
|
#include "src/compiler/change-lowering.h"
|
|
#include "src/compiler/js-graph.h"
|
|
#include "src/compiler/linkage.h"
|
|
#include "src/compiler/node-properties.h"
|
|
#include "src/compiler/simplified-operator.h"
|
|
#include "test/unittests/compiler/compiler-test-utils.h"
|
|
#include "test/unittests/compiler/graph-unittest.h"
|
|
#include "test/unittests/compiler/node-test-utils.h"
|
|
#include "testing/gmock-support.h"
|
|
|
|
using testing::_;
|
|
using testing::AllOf;
|
|
using testing::BitEq;
|
|
using testing::Capture;
|
|
using testing::CaptureEq;
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace compiler {
|
|
|
|
class ChangeLoweringTest : public GraphTest {
|
|
public:
|
|
ChangeLoweringTest() : simplified_(zone()) {}
|
|
~ChangeLoweringTest() OVERRIDE {}
|
|
|
|
virtual MachineType WordRepresentation() const = 0;
|
|
|
|
protected:
|
|
int HeapNumberValueOffset() const {
|
|
STATIC_ASSERT(HeapNumber::kValueOffset % kApiPointerSize == 0);
|
|
return (HeapNumber::kValueOffset / kApiPointerSize) * PointerSize() -
|
|
kHeapObjectTag;
|
|
}
|
|
bool Is32() const { return WordRepresentation() == kRepWord32; }
|
|
int PointerSize() const {
|
|
switch (WordRepresentation()) {
|
|
case kRepWord32:
|
|
return 4;
|
|
case kRepWord64:
|
|
return 8;
|
|
default:
|
|
break;
|
|
}
|
|
UNREACHABLE();
|
|
return 0;
|
|
}
|
|
int SmiMaxValue() const { return -(SmiMinValue() + 1); }
|
|
int SmiMinValue() const {
|
|
return static_cast<int>(0xffffffffu << (SmiValueSize() - 1));
|
|
}
|
|
int SmiShiftAmount() const { return kSmiTagSize + SmiShiftSize(); }
|
|
int SmiShiftSize() const {
|
|
return Is32() ? SmiTagging<4>::SmiShiftSize()
|
|
: SmiTagging<8>::SmiShiftSize();
|
|
}
|
|
int SmiValueSize() const {
|
|
return Is32() ? SmiTagging<4>::SmiValueSize()
|
|
: SmiTagging<8>::SmiValueSize();
|
|
}
|
|
|
|
Reduction Reduce(Node* node) {
|
|
MachineOperatorBuilder machine(zone(), WordRepresentation());
|
|
JSOperatorBuilder javascript(zone());
|
|
JSGraph jsgraph(isolate(), graph(), common(), &javascript, &machine);
|
|
ChangeLowering reducer(&jsgraph);
|
|
return reducer.Reduce(node);
|
|
}
|
|
|
|
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
|
|
|
|
Matcher<Node*> IsAllocateHeapNumber(const Matcher<Node*>& effect_matcher,
|
|
const Matcher<Node*>& control_matcher) {
|
|
return IsCall(_, IsHeapConstant(Unique<HeapObject>::CreateImmovable(
|
|
AllocateHeapNumberStub(isolate()).GetCode())),
|
|
IsNumberConstant(BitEq(0.0)), effect_matcher,
|
|
control_matcher);
|
|
}
|
|
Matcher<Node*> IsLoadHeapNumber(const Matcher<Node*>& value_matcher,
|
|
const Matcher<Node*>& control_matcher) {
|
|
return IsLoad(kMachFloat64, value_matcher,
|
|
IsIntPtrConstant(HeapNumberValueOffset()), graph()->start(),
|
|
control_matcher);
|
|
}
|
|
Matcher<Node*> IsIntPtrConstant(int value) {
|
|
return Is32() ? IsInt32Constant(value) : IsInt64Constant(value);
|
|
}
|
|
Matcher<Node*> IsWordEqual(const Matcher<Node*>& lhs_matcher,
|
|
const Matcher<Node*>& rhs_matcher) {
|
|
return Is32() ? IsWord32Equal(lhs_matcher, rhs_matcher)
|
|
: IsWord64Equal(lhs_matcher, rhs_matcher);
|
|
}
|
|
|
|
private:
|
|
SimplifiedOperatorBuilder simplified_;
|
|
};
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Common.
|
|
|
|
|
|
class ChangeLoweringCommonTest
|
|
: public ChangeLoweringTest,
|
|
public ::testing::WithParamInterface<MachineType> {
|
|
public:
|
|
~ChangeLoweringCommonTest() OVERRIDE {}
|
|
|
|
MachineType WordRepresentation() const FINAL { return GetParam(); }
|
|
};
|
|
|
|
|
|
TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBitToBool) {
|
|
Node* val = Parameter(0);
|
|
Node* node = graph()->NewNode(simplified()->ChangeBitToBool(), val);
|
|
Reduction reduction = Reduce(node);
|
|
ASSERT_TRUE(reduction.Changed());
|
|
EXPECT_THAT(reduction.replacement(),
|
|
IsSelect(static_cast<MachineType>(kTypeBool | kRepTagged), val,
|
|
IsTrueConstant(), IsFalseConstant()));
|
|
}
|
|
|
|
|
|
TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBoolToBit) {
|
|
Node* val = Parameter(0);
|
|
Node* node = graph()->NewNode(simplified()->ChangeBoolToBit(), val);
|
|
Reduction reduction = Reduce(node);
|
|
ASSERT_TRUE(reduction.Changed());
|
|
|
|
EXPECT_THAT(reduction.replacement(), IsWordEqual(val, IsTrueConstant()));
|
|
}
|
|
|
|
|
|
TARGET_TEST_P(ChangeLoweringCommonTest, ChangeFloat64ToTagged) {
|
|
Node* val = Parameter(0);
|
|
Node* node = graph()->NewNode(simplified()->ChangeFloat64ToTagged(), val);
|
|
Reduction reduction = Reduce(node);
|
|
ASSERT_TRUE(reduction.Changed());
|
|
|
|
Node* finish = reduction.replacement();
|
|
Capture<Node*> heap_number;
|
|
EXPECT_THAT(
|
|
finish,
|
|
IsFinish(
|
|
AllOf(CaptureEq(&heap_number),
|
|
IsAllocateHeapNumber(IsValueEffect(val), graph()->start())),
|
|
IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
|
|
CaptureEq(&heap_number),
|
|
IsIntPtrConstant(HeapNumberValueOffset()), val,
|
|
CaptureEq(&heap_number), graph()->start())));
|
|
}
|
|
|
|
|
|
TARGET_TEST_P(ChangeLoweringCommonTest, StringAdd) {
|
|
Node* node =
|
|
graph()->NewNode(simplified()->StringAdd(), Parameter(0), Parameter(1));
|
|
Reduction reduction = Reduce(node);
|
|
EXPECT_FALSE(reduction.Changed());
|
|
}
|
|
|
|
|
|
INSTANTIATE_TEST_CASE_P(ChangeLoweringTest, ChangeLoweringCommonTest,
|
|
::testing::Values(kRepWord32, kRepWord64));
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// 32-bit
|
|
|
|
|
|
class ChangeLowering32Test : public ChangeLoweringTest {
|
|
public:
|
|
~ChangeLowering32Test() OVERRIDE {}
|
|
MachineType WordRepresentation() const FINAL { return kRepWord32; }
|
|
};
|
|
|
|
|
|
TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) {
|
|
Node* val = Parameter(0);
|
|
Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
|
|
NodeProperties::SetBounds(val, Bounds(Type::None(), Type::Signed32()));
|
|
Reduction reduction = Reduce(node);
|
|
ASSERT_TRUE(reduction.Changed());
|
|
|
|
Node* phi = reduction.replacement();
|
|
Capture<Node*> add, branch, heap_number, if_true;
|
|
EXPECT_THAT(
|
|
phi,
|
|
IsPhi(kMachAnyTagged,
|
|
IsFinish(AllOf(CaptureEq(&heap_number),
|
|
IsAllocateHeapNumber(_, CaptureEq(&if_true))),
|
|
IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
|
|
CaptureEq(&heap_number),
|
|
IsIntPtrConstant(HeapNumberValueOffset()),
|
|
IsChangeInt32ToFloat64(val),
|
|
CaptureEq(&heap_number), CaptureEq(&if_true))),
|
|
IsProjection(
|
|
0, AllOf(CaptureEq(&add), IsInt32AddWithOverflow(val, val))),
|
|
IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
|
|
IsIfFalse(AllOf(CaptureEq(&branch),
|
|
IsBranch(IsProjection(1, CaptureEq(&add)),
|
|
graph()->start()))))));
|
|
}
|
|
|
|
|
|
TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTaggedSmall) {
|
|
Node* val = Parameter(0);
|
|
Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
|
|
NodeProperties::SetBounds(val, Bounds(Type::None(), Type::Signed31()));
|
|
Reduction reduction = Reduce(node);
|
|
ASSERT_TRUE(reduction.Changed());
|
|
|
|
Node* change = reduction.replacement();
|
|
Capture<Node*> add, branch, heap_number, if_true;
|
|
EXPECT_THAT(change, IsWord32Shl(val, IsInt32Constant(SmiShiftAmount())));
|
|
}
|
|
|
|
|
|
TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
|
|
STATIC_ASSERT(kSmiTag == 0);
|
|
STATIC_ASSERT(kSmiTagSize == 1);
|
|
|
|
Node* val = Parameter(0);
|
|
Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
|
|
Reduction reduction = Reduce(node);
|
|
ASSERT_TRUE(reduction.Changed());
|
|
|
|
Node* phi = reduction.replacement();
|
|
Capture<Node*> branch, if_true;
|
|
EXPECT_THAT(
|
|
phi,
|
|
IsPhi(
|
|
kMachFloat64, IsLoadHeapNumber(val, CaptureEq(&if_true)),
|
|
IsChangeInt32ToFloat64(
|
|
IsWord32Sar(val, IsInt32Constant(SmiShiftAmount()))),
|
|
IsMerge(
|
|
AllOf(CaptureEq(&if_true),
|
|
IsIfTrue(AllOf(
|
|
CaptureEq(&branch),
|
|
IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
|
|
graph()->start())))),
|
|
IsIfFalse(CaptureEq(&branch)))));
|
|
}
|
|
|
|
|
|
TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) {
|
|
STATIC_ASSERT(kSmiTag == 0);
|
|
STATIC_ASSERT(kSmiTagSize == 1);
|
|
|
|
Node* val = Parameter(0);
|
|
Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
|
|
Reduction reduction = Reduce(node);
|
|
ASSERT_TRUE(reduction.Changed());
|
|
|
|
Node* phi = reduction.replacement();
|
|
Capture<Node*> branch, if_true;
|
|
EXPECT_THAT(
|
|
phi,
|
|
IsPhi(kMachInt32,
|
|
IsChangeFloat64ToInt32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
|
|
IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())),
|
|
IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
|
|
IsIfFalse(AllOf(
|
|
CaptureEq(&branch),
|
|
IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
|
|
graph()->start()))))));
|
|
}
|
|
|
|
|
|
TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToUint32) {
|
|
STATIC_ASSERT(kSmiTag == 0);
|
|
STATIC_ASSERT(kSmiTagSize == 1);
|
|
|
|
Node* val = Parameter(0);
|
|
Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val);
|
|
Reduction reduction = Reduce(node);
|
|
ASSERT_TRUE(reduction.Changed());
|
|
|
|
Node* phi = reduction.replacement();
|
|
Capture<Node*> branch, if_true;
|
|
EXPECT_THAT(
|
|
phi,
|
|
IsPhi(kMachUint32,
|
|
IsChangeFloat64ToUint32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
|
|
IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())),
|
|
IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
|
|
IsIfFalse(AllOf(
|
|
CaptureEq(&branch),
|
|
IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
|
|
graph()->start()))))));
|
|
}
|
|
|
|
|
|
TARGET_TEST_F(ChangeLowering32Test, ChangeUint32ToTagged) {
|
|
STATIC_ASSERT(kSmiTag == 0);
|
|
STATIC_ASSERT(kSmiTagSize == 1);
|
|
|
|
Node* val = Parameter(0);
|
|
Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val);
|
|
Reduction reduction = Reduce(node);
|
|
ASSERT_TRUE(reduction.Changed());
|
|
|
|
Node* phi = reduction.replacement();
|
|
Capture<Node*> branch, heap_number, if_false;
|
|
EXPECT_THAT(
|
|
phi,
|
|
IsPhi(
|
|
kMachAnyTagged, IsWord32Shl(val, IsInt32Constant(SmiShiftAmount())),
|
|
IsFinish(AllOf(CaptureEq(&heap_number),
|
|
IsAllocateHeapNumber(_, CaptureEq(&if_false))),
|
|
IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
|
|
CaptureEq(&heap_number),
|
|
IsInt32Constant(HeapNumberValueOffset()),
|
|
IsChangeUint32ToFloat64(val),
|
|
CaptureEq(&heap_number), CaptureEq(&if_false))),
|
|
IsMerge(
|
|
IsIfTrue(AllOf(CaptureEq(&branch),
|
|
IsBranch(IsUint32LessThanOrEqual(
|
|
val, IsInt32Constant(SmiMaxValue())),
|
|
graph()->start()))),
|
|
AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// 64-bit
|
|
|
|
|
|
class ChangeLowering64Test : public ChangeLoweringTest {
|
|
public:
|
|
~ChangeLowering64Test() OVERRIDE {}
|
|
MachineType WordRepresentation() const FINAL { return kRepWord64; }
|
|
};
|
|
|
|
|
|
TARGET_TEST_F(ChangeLowering64Test, ChangeInt32ToTagged) {
|
|
Node* val = Parameter(0);
|
|
Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
|
|
Reduction reduction = Reduce(node);
|
|
ASSERT_TRUE(reduction.Changed());
|
|
|
|
EXPECT_THAT(reduction.replacement(),
|
|
IsWord64Shl(IsChangeInt32ToInt64(val),
|
|
IsInt64Constant(SmiShiftAmount())));
|
|
}
|
|
|
|
|
|
TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
|
|
STATIC_ASSERT(kSmiTag == 0);
|
|
STATIC_ASSERT(kSmiTagSize == 1);
|
|
|
|
Node* val = Parameter(0);
|
|
Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
|
|
Reduction reduction = Reduce(node);
|
|
ASSERT_TRUE(reduction.Changed());
|
|
|
|
Node* phi = reduction.replacement();
|
|
Capture<Node*> branch, if_true;
|
|
EXPECT_THAT(
|
|
phi,
|
|
IsPhi(
|
|
kMachFloat64, IsLoadHeapNumber(val, CaptureEq(&if_true)),
|
|
IsChangeInt32ToFloat64(IsTruncateInt64ToInt32(
|
|
IsWord64Sar(val, IsInt64Constant(SmiShiftAmount())))),
|
|
IsMerge(
|
|
AllOf(CaptureEq(&if_true),
|
|
IsIfTrue(AllOf(
|
|
CaptureEq(&branch),
|
|
IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)),
|
|
graph()->start())))),
|
|
IsIfFalse(CaptureEq(&branch)))));
|
|
}
|
|
|
|
|
|
TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) {
|
|
STATIC_ASSERT(kSmiTag == 0);
|
|
STATIC_ASSERT(kSmiTagSize == 1);
|
|
|
|
Node* val = Parameter(0);
|
|
Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
|
|
Reduction reduction = Reduce(node);
|
|
ASSERT_TRUE(reduction.Changed());
|
|
|
|
Node* phi = reduction.replacement();
|
|
Capture<Node*> branch, if_true;
|
|
EXPECT_THAT(
|
|
phi,
|
|
IsPhi(kMachInt32,
|
|
IsChangeFloat64ToInt32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
|
|
IsTruncateInt64ToInt32(
|
|
IsWord64Sar(val, IsInt64Constant(SmiShiftAmount()))),
|
|
IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
|
|
IsIfFalse(AllOf(
|
|
CaptureEq(&branch),
|
|
IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)),
|
|
graph()->start()))))));
|
|
}
|
|
|
|
|
|
TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToUint32) {
|
|
STATIC_ASSERT(kSmiTag == 0);
|
|
STATIC_ASSERT(kSmiTagSize == 1);
|
|
|
|
Node* val = Parameter(0);
|
|
Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val);
|
|
Reduction reduction = Reduce(node);
|
|
ASSERT_TRUE(reduction.Changed());
|
|
|
|
Node* phi = reduction.replacement();
|
|
Capture<Node*> branch, if_true;
|
|
EXPECT_THAT(
|
|
phi,
|
|
IsPhi(kMachUint32,
|
|
IsChangeFloat64ToUint32(IsLoadHeapNumber(val, CaptureEq(&if_true))),
|
|
IsTruncateInt64ToInt32(
|
|
IsWord64Sar(val, IsInt64Constant(SmiShiftAmount()))),
|
|
IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
|
|
IsIfFalse(AllOf(
|
|
CaptureEq(&branch),
|
|
IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)),
|
|
graph()->start()))))));
|
|
}
|
|
|
|
|
|
TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) {
|
|
STATIC_ASSERT(kSmiTag == 0);
|
|
STATIC_ASSERT(kSmiTagSize == 1);
|
|
|
|
Node* val = Parameter(0);
|
|
Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val);
|
|
Reduction reduction = Reduce(node);
|
|
ASSERT_TRUE(reduction.Changed());
|
|
|
|
Node* phi = reduction.replacement();
|
|
Capture<Node*> branch, heap_number, if_false;
|
|
EXPECT_THAT(
|
|
phi,
|
|
IsPhi(
|
|
kMachAnyTagged, IsWord64Shl(IsChangeUint32ToUint64(val),
|
|
IsInt64Constant(SmiShiftAmount())),
|
|
IsFinish(AllOf(CaptureEq(&heap_number),
|
|
IsAllocateHeapNumber(_, CaptureEq(&if_false))),
|
|
IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier),
|
|
CaptureEq(&heap_number),
|
|
IsInt64Constant(HeapNumberValueOffset()),
|
|
IsChangeUint32ToFloat64(val),
|
|
CaptureEq(&heap_number), CaptureEq(&if_false))),
|
|
IsMerge(
|
|
IsIfTrue(AllOf(CaptureEq(&branch),
|
|
IsBranch(IsUint32LessThanOrEqual(
|
|
val, IsInt32Constant(SmiMaxValue())),
|
|
graph()->start()))),
|
|
AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
|
|
}
|
|
|
|
} // namespace compiler
|
|
} // namespace internal
|
|
} // namespace v8
|