Commit 936d7218 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

[turbofan] Support lowering of ChangeFloat64ToTagged/ChangeTaggedToInt32.

Adds new ValueEffect operator to ensure proper scheduling of
AllocateHeapNumber call nodes.

Also includes some refactoring to reduce code duplication.

TEST=compiler-unittests
R=jarin@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23175 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 37ce51e0
......@@ -15,16 +15,19 @@ ChangeLowering::~ChangeLowering() {}
Reduction ChangeLowering::Reduce(Node* node) {
Node* control = graph()->start();
Node* effect = control;
switch (node->opcode()) {
case IrOpcode::kChangeBitToBool:
return ChangeBitToBool(node->InputAt(0), control);
case IrOpcode::kChangeBoolToBit:
return ChangeBoolToBit(node->InputAt(0));
case IrOpcode::kChangeFloat64ToTagged:
return ChangeFloat64ToTagged(node->InputAt(0), control);
case IrOpcode::kChangeInt32ToTagged:
return ChangeInt32ToTagged(node->InputAt(0), effect, control);
return ChangeInt32ToTagged(node->InputAt(0), control);
case IrOpcode::kChangeTaggedToFloat64:
return ChangeTaggedToFloat64(node->InputAt(0), effect, control);
return ChangeTaggedToFloat64(node->InputAt(0), control);
case IrOpcode::kChangeTaggedToInt32:
return ChangeTaggedToInt32(node->InputAt(0), control);
default:
return NoChange();
}
......@@ -77,49 +80,67 @@ Reduction ChangeLowering::ChangeBoolToBit(Node* val) {
}
Reduction ChangeLowering::ChangeInt32ToTagged(Node* val, Node* effect,
Node* control) {
Reduction ChangeLowering::ChangeFloat64ToTagged(Node* val, Node* control) {
return Replace(AllocateHeapNumberWithValue(val, control));
}
Reduction ChangeLowering::ChangeInt32ToTagged(Node* val, Node* control) {
if (machine()->is64()) {
return Replace(
graph()->NewNode(machine()->WordShl(), val, SmiShiftBitsConstant()));
}
Node* context = jsgraph()->SmiConstant(0);
Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), val, val);
Node* ovf = graph()->NewNode(common()->Projection(1), add);
Node* branch = graph()->NewNode(common()->Branch(), ovf, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* number = graph()->NewNode(machine()->ChangeInt32ToFloat64(), val);
const Runtime::Function* fn =
Runtime::FunctionForId(Runtime::kAllocateHeapNumber);
DCHECK_EQ(0, fn->nargs);
CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(
fn->function_id, 0, Operator::kNoProperties);
Node* heap_number = graph()->NewNode(
common()->Call(desc), jsgraph()->CEntryStubConstant(),
jsgraph()->ExternalConstant(ExternalReference(fn, isolate())),
jsgraph()->Int32Constant(fn->nargs), context, effect, if_true);
Node* store = graph()->NewNode(
machine()->Store(kMachFloat64, kNoWriteBarrier), heap_number,
HeapNumberValueIndexConstant(), number, heap_number, if_true);
Node* finish = graph()->NewNode(common()->Finish(1), heap_number, store);
Node* heap_number = AllocateHeapNumberWithValue(
graph()->NewNode(machine()->ChangeInt32ToFloat64(), val), if_true);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* smi = graph()->NewNode(common()->Projection(0), add);
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
Node* phi = graph()->NewNode(common()->Phi(2), finish, smi, merge);
Node* phi = graph()->NewNode(common()->Phi(2), heap_number, smi, merge);
return Replace(phi);
}
Reduction ChangeLowering::ChangeTaggedToFloat64(Node* val, Node* effect,
Node* control) {
Reduction ChangeLowering::ChangeTaggedToInt32(Node* val, Node* control) {
STATIC_ASSERT(kSmiTag == 0);
STATIC_ASSERT(kSmiTagMask == 1);
Node* tag = graph()->NewNode(machine()->WordAnd(), val,
jsgraph()->Int32Constant(kSmiTagMask));
Node* branch = graph()->NewNode(common()->Branch(), tag, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* load = graph()->NewNode(
machine()->Load(kMachFloat64), val, HeapNumberValueIndexConstant(),
graph()->NewNode(common()->ControlEffect(), if_true));
Node* change = graph()->NewNode(machine()->ChangeFloat64ToInt32(), load);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* integer =
graph()->NewNode(machine()->WordSar(), val, SmiShiftBitsConstant());
Node* number =
machine()->is64()
? graph()->NewNode(machine()->ConvertInt64ToInt32(), integer)
: integer;
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
Node* phi = graph()->NewNode(common()->Phi(2), change, number, merge);
return Replace(phi);
}
Reduction ChangeLowering::ChangeTaggedToFloat64(Node* val, Node* control) {
STATIC_ASSERT(kSmiTag == 0);
STATIC_ASSERT(kSmiTagMask == 1);
Node* tag = graph()->NewNode(machine()->WordAnd(), val,
......@@ -157,6 +178,27 @@ CommonOperatorBuilder* ChangeLowering::common() const {
return jsgraph()->common();
}
Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node* control) {
// The AllocateHeapNumber() runtime function does not use the context, so we
// can safely pass in Smi zero here.
Node* context = jsgraph()->ZeroConstant();
Node* effect = graph()->NewNode(common()->ValueEffect(1), value);
const Runtime::Function* function =
Runtime::FunctionForId(Runtime::kAllocateHeapNumber);
DCHECK_EQ(0, function->nargs);
CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(
function->function_id, 0, Operator::kNoProperties);
Node* heap_number = graph()->NewNode(
common()->Call(desc), jsgraph()->CEntryStubConstant(),
jsgraph()->ExternalConstant(ExternalReference(function, isolate())),
jsgraph()->Int32Constant(function->nargs), context, effect, control);
Node* store = graph()->NewNode(
machine()->Store(kMachFloat64, kNoWriteBarrier), heap_number,
HeapNumberValueIndexConstant(), value, heap_number, control);
return graph()->NewNode(common()->Finish(1), heap_number, store);
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -32,8 +32,10 @@ class ChangeLowering V8_FINAL : public Reducer {
Reduction ChangeBitToBool(Node* val, Node* control);
Reduction ChangeBoolToBit(Node* val);
Reduction ChangeInt32ToTagged(Node* val, Node* effect, Node* control);
Reduction ChangeTaggedToFloat64(Node* val, Node* effect, Node* control);
Reduction ChangeFloat64ToTagged(Node* val, Node* control);
Reduction ChangeInt32ToTagged(Node* val, Node* control);
Reduction ChangeTaggedToFloat64(Node* val, Node* control);
Reduction ChangeTaggedToInt32(Node* val, Node* control);
Graph* graph() const;
Isolate* isolate() const;
......@@ -43,6 +45,8 @@ class ChangeLowering V8_FINAL : public Reducer {
MachineOperatorBuilder* machine() const { return machine_; }
private:
Node* AllocateHeapNumberWithValue(Node* value, Node* control);
JSGraph* jsgraph_;
Linkage* linkage_;
MachineOperatorBuilder* machine_;
......
......@@ -134,6 +134,11 @@ class CommonOperatorBuilder {
return new (zone_) SimpleOperator(IrOpcode::kControlEffect, Operator::kPure,
0, 0, "ControlEffect");
}
Operator* ValueEffect(int arguments) {
DCHECK(arguments > 0); // Disallow empty value effects.
return new (zone_) SimpleOperator(IrOpcode::kValueEffect, Operator::kPure,
arguments, 0, "ValueEffect");
}
Operator* Finish(int arguments) {
DCHECK(arguments > 0); // Disallow empty finishes.
return new (zone_) Operator1<int>(IrOpcode::kFinish, Operator::kPure, 1, 1,
......
......@@ -34,6 +34,7 @@
V(Phi) \
V(EffectPhi) \
V(ControlEffect) \
V(ValueEffect) \
V(Finish) \
V(FrameState) \
V(StateValues) \
......
......@@ -91,6 +91,7 @@ inline bool OperatorProperties::HasValueOutput(Operator* op) {
inline bool OperatorProperties::HasEffectOutput(Operator* op) {
return op->opcode() == IrOpcode::kStart ||
op->opcode() == IrOpcode::kControlEffect ||
op->opcode() == IrOpcode::kValueEffect ||
(op->opcode() != IrOpcode::kFinish && GetEffectInputCount(op) > 0);
}
......
......@@ -272,6 +272,11 @@ Bounds Typer::Visitor::TypeControlEffect(Node* node) {
}
Bounds Typer::Visitor::TypeValueEffect(Node* node) {
return Bounds(Type::None(zone()));
}
Bounds Typer::Visitor::TypeFinish(Node* node) { return OperandType(node, 0); }
......
......@@ -19,20 +19,52 @@ namespace v8 {
namespace internal {
namespace compiler {
template <typename T>
// TODO(bmeurer): Find a new home for these functions.
inline std::ostream& operator<<(std::ostream& os, const MachineType& type) {
OStringStream ost;
ost << type;
return os << ost.c_str();
}
class ChangeLoweringTest : public GraphTest {
public:
static const size_t kPointerSize = sizeof(T);
static const MachineType kWordRepresentation =
(kPointerSize == 4) ? kRepWord32 : kRepWord64;
STATIC_ASSERT(HeapNumber::kValueOffset % kApiPointerSize == 0);
static const int kHeapNumberValueOffset = static_cast<int>(
(HeapNumber::kValueOffset / kApiPointerSize) * kPointerSize);
ChangeLoweringTest() : simplified_(zone()) {}
virtual ~ChangeLoweringTest() {}
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 SmiShiftAmount() const { return kSmiTagSize + SmiShiftSize(); }
int SmiShiftSize() const {
// TODO(turbofan): Work-around for weird GCC 4.6 linker issue:
// src/compiler/change-lowering.cc:46: undefined reference to
// `v8::internal::SmiTagging<4u>::kSmiShiftSize'
// src/compiler/change-lowering.cc:46: undefined reference to
// `v8::internal::SmiTagging<8u>::kSmiShiftSize'
STATIC_ASSERT(SmiTagging<4>::kSmiShiftSize == 0);
STATIC_ASSERT(SmiTagging<8>::kSmiShiftSize == 31);
return Is32() ? 0 : 31;
}
Node* Parameter(int32_t index = 0) {
return graph()->NewNode(common()->Parameter(index), graph()->start());
}
......@@ -42,20 +74,35 @@ class ChangeLoweringTest : public GraphTest {
JSGraph jsgraph(graph(), common(), &typer);
CompilationInfo info(isolate(), zone());
Linkage linkage(&info);
MachineOperatorBuilder machine(zone(), kWordRepresentation);
MachineOperatorBuilder machine(zone(), WordRepresentation());
ChangeLowering reducer(&jsgraph, &linkage, &machine);
return reducer.Reduce(node);
}
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
PrintableUnique<HeapObject> true_unique() {
return PrintableUnique<HeapObject>::CreateImmovable(
zone(), factory()->true_value());
Matcher<Node*> IsAllocateHeapNumber(const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher) {
return IsCall(
_, IsHeapConstant(PrintableUnique<HeapObject>::CreateImmovable(
zone(), CEntryStub(isolate(), 1).GetCode())),
IsExternalConstant(ExternalReference(
Runtime::FunctionForId(Runtime::kAllocateHeapNumber), isolate())),
IsInt32Constant(0), IsNumberConstant(0.0), effect_matcher,
control_matcher);
}
PrintableUnique<HeapObject> false_unique() {
return PrintableUnique<HeapObject>::CreateImmovable(
zone(), factory()->false_value());
Matcher<Node*> IsFalse() {
return IsHeapConstant(PrintableUnique<HeapObject>::CreateImmovable(
zone(), factory()->false_value()));
}
Matcher<Node*> IsTrue() {
return IsHeapConstant(PrintableUnique<HeapObject>::CreateImmovable(
zone(), factory()->true_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:
......@@ -63,53 +110,94 @@ class ChangeLoweringTest : public GraphTest {
};
typedef ::testing::Types<int32_t, int64_t> ChangeLoweringTypes;
TYPED_TEST_CASE(ChangeLoweringTest, ChangeLoweringTypes);
// -----------------------------------------------------------------------------
// Common.
namespace {
TARGET_TYPED_TEST(ChangeLoweringTest, ChangeBitToBool) {
Node* val = this->Parameter(0);
Node* node =
this->graph()->NewNode(this->simplified()->ChangeBitToBool(), val);
Reduction reduction = this->Reduce(node);
class Common : public ChangeLoweringTest,
public ::testing::WithParamInterface<MachineType> {
public:
virtual ~Common() {}
virtual MachineType WordRepresentation() const V8_FINAL V8_OVERRIDE {
return GetParam();
}
};
TARGET_TEST_P(Common, ChangeBitToBool) {
Node* val = Parameter(0);
Node* node = graph()->NewNode(simplified()->ChangeBitToBool(), val);
Reduction reduction = Reduce(node);
ASSERT_TRUE(reduction.Changed());
Node* phi = reduction.replacement();
Capture<Node*> branch;
EXPECT_THAT(
phi, IsPhi(IsHeapConstant(this->true_unique()),
IsHeapConstant(this->false_unique()),
IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
IsBranch(val, this->graph()->start()))),
IsIfFalse(CaptureEq(&branch)))));
EXPECT_THAT(phi,
IsPhi(IsTrue(), IsFalse(),
IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
IsBranch(val, graph()->start()))),
IsIfFalse(CaptureEq(&branch)))));
}
TARGET_TYPED_TEST(ChangeLoweringTest, StringAdd) {
Node* node = this->graph()->NewNode(this->simplified()->StringAdd(),
this->Parameter(0), this->Parameter(1));
Reduction reduction = this->Reduce(node);
EXPECT_FALSE(reduction.Changed());
}
TARGET_TEST_P(Common, ChangeBoolToBit) {
Node* val = Parameter(0);
Node* node = graph()->NewNode(simplified()->ChangeBoolToBit(), val);
Reduction reduction = Reduce(node);
ASSERT_TRUE(reduction.Changed());
class ChangeLowering32Test : public ChangeLoweringTest<int32_t> {
public:
virtual ~ChangeLowering32Test() {}
};
EXPECT_THAT(reduction.replacement(), IsWordEqual(val, IsTrue()));
}
TARGET_TEST_F(ChangeLowering32Test, ChangeBoolToBit) {
TARGET_TEST_P(Common, ChangeFloat64ToTagged) {
Node* val = Parameter(0);
Node* node = graph()->NewNode(simplified()->ChangeBoolToBit(), val);
Node* node = graph()->NewNode(simplified()->ChangeFloat64ToTagged(), val);
Reduction reduction = Reduce(node);
ASSERT_TRUE(reduction.Changed());
EXPECT_THAT(reduction.replacement(),
IsWord32Equal(val, IsHeapConstant(true_unique())));
Node* finish = reduction.replacement();
Capture<Node*> heap_number;
EXPECT_THAT(
finish,
IsFinish(
AllOf(CaptureEq(&heap_number),
IsAllocateHeapNumber(IsValueEffect(val), graph()->start())),
IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number),
IsInt32Constant(HeapNumberValueOffset()), val,
CaptureEq(&heap_number), graph()->start())));
}
TARGET_TEST_P(Common, StringAdd) {
Node* node =
graph()->NewNode(simplified()->StringAdd(), Parameter(0), Parameter(1));
Reduction reduction = Reduce(node);
EXPECT_FALSE(reduction.Changed());
}
} // namespace
INSTANTIATE_TEST_CASE_P(ChangeLoweringTest, Common,
::testing::Values(kRepWord32, kRepWord64));
// -----------------------------------------------------------------------------
// 32-bit
class ChangeLowering32Test : public ChangeLoweringTest {
public:
virtual ~ChangeLowering32Test() {}
virtual MachineType WordRepresentation() const V8_FINAL V8_OVERRIDE {
return kRepWord32;
}
};
TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) {
Node* val = Parameter(0);
Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
......@@ -118,32 +206,21 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) {
Node* phi = reduction.replacement();
Capture<Node*> add, branch, heap_number, if_true;
const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag;
EXPECT_THAT(
phi,
IsPhi(
IsFinish(
AllOf(
CaptureEq(&heap_number),
IsCall(
_, IsHeapConstant(
PrintableUnique<HeapObject>::CreateImmovable(
zone(), CEntryStub(isolate(), 1).GetCode())),
IsExternalConstant(ExternalReference(
Runtime::FunctionForId(Runtime::kAllocateHeapNumber),
isolate())),
IsInt32Constant(0), IsNumberConstant(0.0),
graph()->start(), CaptureEq(&if_true))),
IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number),
IsInt32Constant(kValueOffset),
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()))))));
IsPhi(IsFinish(
AllOf(CaptureEq(&heap_number),
IsAllocateHeapNumber(_, CaptureEq(&if_true))),
IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number),
IsInt32Constant(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()))))));
}
......@@ -156,18 +233,15 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
Reduction reduction = Reduce(node);
ASSERT_TRUE(reduction.Changed());
const int32_t kShiftAmount =
kSmiTagSize + SmiTagging<kPointerSize>::kSmiShiftSize;
const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag;
Node* phi = reduction.replacement();
Capture<Node*> branch, if_true;
EXPECT_THAT(
phi,
IsPhi(
IsLoad(kMachFloat64, val, IsInt32Constant(kValueOffset),
IsLoad(kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
IsControlEffect(CaptureEq(&if_true))),
IsChangeInt32ToFloat64(
IsWord32Sar(val, IsInt32Constant(kShiftAmount))),
IsWord32Sar(val, IsInt32Constant(SmiShiftAmount()))),
IsMerge(
AllOf(CaptureEq(&if_true),
IsIfTrue(AllOf(
......@@ -178,33 +252,52 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
}
class ChangeLowering64Test : public ChangeLoweringTest<int64_t> {
public:
virtual ~ChangeLowering64Test() {}
};
TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) {
STATIC_ASSERT(kSmiTag == 0);
STATIC_ASSERT(kSmiTagSize == 1);
TARGET_TEST_F(ChangeLowering64Test, ChangeBoolToBit) {
Node* val = Parameter(0);
Node* node = graph()->NewNode(simplified()->ChangeBoolToBit(), val);
Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
Reduction reduction = Reduce(node);
ASSERT_TRUE(reduction.Changed());
EXPECT_THAT(reduction.replacement(),
IsWord64Equal(val, IsHeapConstant(true_unique())));
Node* phi = reduction.replacement();
Capture<Node*> branch, if_true;
EXPECT_THAT(
phi,
IsPhi(IsChangeFloat64ToInt32(IsLoad(
kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
IsControlEffect(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()))))));
}
// -----------------------------------------------------------------------------
// 64-bit
class ChangeLowering64Test : public ChangeLoweringTest {
public:
virtual ~ChangeLowering64Test() {}
virtual MachineType WordRepresentation() const V8_FINAL V8_OVERRIDE {
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());
const int32_t kShiftAmount =
kSmiTagSize + SmiTagging<kPointerSize>::kSmiShiftSize;
EXPECT_THAT(reduction.replacement(),
IsWord64Shl(val, IsInt32Constant(kShiftAmount)));
IsWord64Shl(val, IsInt32Constant(SmiShiftAmount())));
}
......@@ -217,18 +310,15 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
Reduction reduction = Reduce(node);
ASSERT_TRUE(reduction.Changed());
const int32_t kShiftAmount =
kSmiTagSize + SmiTagging<kPointerSize>::kSmiShiftSize;
const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag;
Node* phi = reduction.replacement();
Capture<Node*> branch, if_true;
EXPECT_THAT(
phi,
IsPhi(
IsLoad(kMachFloat64, val, IsInt32Constant(kValueOffset),
IsLoad(kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
IsControlEffect(CaptureEq(&if_true))),
IsChangeInt32ToFloat64(IsConvertInt64ToInt32(
IsWord64Sar(val, IsInt32Constant(kShiftAmount)))),
IsWord64Sar(val, IsInt32Constant(SmiShiftAmount())))),
IsMerge(
AllOf(CaptureEq(&if_true),
IsIfTrue(AllOf(
......@@ -238,6 +328,32 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
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(IsChangeFloat64ToInt32(IsLoad(
kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
IsControlEffect(CaptureEq(&if_true)))),
IsConvertInt64ToInt32(
IsWord64Sar(val, IsInt32Constant(SmiShiftAmount()))),
IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
IsIfFalse(AllOf(
CaptureEq(&branch),
IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
graph()->start()))))));
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -10,6 +10,9 @@ namespace v8 {
namespace internal {
namespace compiler {
static const int kArguments[] = {1, 5, 6, 42, 100, 10000, kMaxInt};
CommonOperatorTest::CommonOperatorTest() : common_(zone()) {}
......@@ -26,8 +29,19 @@ TEST_F(CommonOperatorTest, ControlEffect) {
}
TEST_F(CommonOperatorTest, ValueEffect) {
TRACED_FOREACH(int, arguments, kArguments) {
Operator* op = common()->ValueEffect(arguments);
EXPECT_EQ(arguments, OperatorProperties::GetValueInputCount(op));
EXPECT_EQ(arguments, OperatorProperties::GetTotalInputCount(op));
EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
EXPECT_EQ(1, OperatorProperties::GetEffectOutputCount(op));
EXPECT_EQ(0, OperatorProperties::GetValueOutputCount(op));
}
}
TEST_F(CommonOperatorTest, Finish) {
static const int kArguments[] = {1, 5, 6, 42, 100, 10000, kMaxInt};
TRACED_FOREACH(int, arguments, kArguments) {
Operator* op = common()->Finish(arguments);
EXPECT_EQ(1, OperatorProperties::GetValueInputCount(op));
......
......@@ -33,6 +33,16 @@ namespace compiler {
#endif
// The TARGET_TEST_P(Case, Name) macro works just like
// TEST_P(Case, Name), except that the test is disabled
// if the platform is not a supported TurboFan target.
#if V8_TURBOFAN_TARGET
#define TARGET_TEST_P(Case, Name) TEST_P(Case, Name)
#else
#define TARGET_TEST_P(Case, Name) TEST_P(Case, DISABLED_##Name)
#endif
// The TARGET_TYPED_TEST(Case, Name) macro works just like
// TYPED_TEST(Case, Name), except that the test is disabled
// if the platform is not a supported TurboFan target.
......
......@@ -8,6 +8,7 @@
#include "src/compiler/node-properties-inl.h"
using testing::_;
using testing::MakeMatcher;
using testing::MatcherInterface;
using testing::MatchResultListener;
......@@ -567,6 +568,11 @@ Matcher<Node*> IsControlEffect(const Matcher<Node*>& control_matcher) {
}
Matcher<Node*> IsValueEffect(const Matcher<Node*>& value_matcher) {
return MakeMatcher(new IsUnopMatcher(IrOpcode::kValueEffect, value_matcher));
}
Matcher<Node*> IsFinish(const Matcher<Node*>& value_matcher,
const Matcher<Node*>& effect_matcher) {
return MakeMatcher(new IsFinishMatcher(value_matcher, effect_matcher));
......@@ -671,6 +677,7 @@ IS_BINOP_MATCHER(Int32AddWithOverflow)
return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \
}
IS_UNOP_MATCHER(ConvertInt64ToInt32)
IS_UNOP_MATCHER(ChangeFloat64ToInt32)
IS_UNOP_MATCHER(ChangeInt32ToFloat64)
#undef IS_UNOP_MATCHER
......
......@@ -35,6 +35,7 @@ class GraphTest : public CommonOperatorTest {
using ::testing::Matcher;
Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,
......@@ -42,6 +43,7 @@ Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,
Matcher<Node*> IsIfTrue(const Matcher<Node*>& control_matcher);
Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher);
Matcher<Node*> IsControlEffect(const Matcher<Node*>& control_matcher);
Matcher<Node*> IsValueEffect(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsFinish(const Matcher<Node*>& value_matcher,
const Matcher<Node*>& effect_matcher);
Matcher<Node*> IsExternalConstant(
......@@ -93,6 +95,7 @@ Matcher<Node*> IsWord64Equal(const Matcher<Node*>& lhs_matcher,
Matcher<Node*> IsInt32AddWithOverflow(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsConvertInt64ToInt32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsChangeFloat64ToInt32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsChangeInt32ToFloat64(const Matcher<Node*>& input_matcher);
} // namespace compiler
......
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