From: bmeurer@chromium.org Date: Tue, 19 Aug 2014 04:54:06 +0000 (+0000) Subject: [turbofan] Support lowering of ChangeFloat64ToTagged/ChangeTaggedToInt32. X-Git-Tag: upstream/4.7.83~7574 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=936d7218b46c6be052ee3b4aea42b81abc05283e;p=platform%2Fupstream%2Fv8.git [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 --- diff --git a/src/compiler/change-lowering.cc b/src/compiler/change-lowering.cc index 4863f8fee..03eaa398a 100644 --- a/src/compiler/change-lowering.cc +++ b/src/compiler/change-lowering.cc @@ -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 diff --git a/src/compiler/change-lowering.h b/src/compiler/change-lowering.h index 93ba14206..55496e6e1 100644 --- a/src/compiler/change-lowering.h +++ b/src/compiler/change-lowering.h @@ -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_; diff --git a/src/compiler/common-operator.h b/src/compiler/common-operator.h index 2c5f1b66f..0b51088ca 100644 --- a/src/compiler/common-operator.h +++ b/src/compiler/common-operator.h @@ -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(IrOpcode::kFinish, Operator::kPure, 1, 1, diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index a3e1ba493..6c9fc0b94 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -34,6 +34,7 @@ V(Phi) \ V(EffectPhi) \ V(ControlEffect) \ + V(ValueEffect) \ V(Finish) \ V(FrameState) \ V(StateValues) \ diff --git a/src/compiler/operator-properties-inl.h b/src/compiler/operator-properties-inl.h index 582d5e4ca..d1b1b3c01 100644 --- a/src/compiler/operator-properties-inl.h +++ b/src/compiler/operator-properties-inl.h @@ -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); } diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 6a0127e60..73fe41d58 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -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); } diff --git a/test/compiler-unittests/change-lowering-unittest.cc b/test/compiler-unittests/change-lowering-unittest.cc index 329acfff1..46c07fd12 100644 --- a/test/compiler-unittests/change-lowering-unittest.cc +++ b/test/compiler-unittests/change-lowering-unittest.cc @@ -19,20 +19,52 @@ namespace v8 { namespace internal { namespace compiler { -template +// 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( - (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 true_unique() { - return PrintableUnique::CreateImmovable( - zone(), factory()->true_value()); + Matcher IsAllocateHeapNumber(const Matcher& effect_matcher, + const Matcher& control_matcher) { + return IsCall( + _, IsHeapConstant(PrintableUnique::CreateImmovable( + zone(), CEntryStub(isolate(), 1).GetCode())), + IsExternalConstant(ExternalReference( + Runtime::FunctionForId(Runtime::kAllocateHeapNumber), isolate())), + IsInt32Constant(0), IsNumberConstant(0.0), effect_matcher, + control_matcher); } - PrintableUnique false_unique() { - return PrintableUnique::CreateImmovable( - zone(), factory()->false_value()); + Matcher IsFalse() { + return IsHeapConstant(PrintableUnique::CreateImmovable( + zone(), factory()->false_value())); + } + Matcher IsTrue() { + return IsHeapConstant(PrintableUnique::CreateImmovable( + zone(), factory()->true_value())); + } + Matcher IsWordEqual(const Matcher& lhs_matcher, + const Matcher& 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 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 { + 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 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 { - 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 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 add, branch, heap_number, if_true; - const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag; EXPECT_THAT( phi, - IsPhi( - IsFinish( - AllOf( - CaptureEq(&heap_number), - IsCall( - _, IsHeapConstant( - PrintableUnique::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::kSmiShiftSize; - const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag; Node* phi = reduction.replacement(); Capture 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 { - 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 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::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::kSmiShiftSize; - const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag; Node* phi = reduction.replacement(); Capture 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 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 diff --git a/test/compiler-unittests/common-operator-unittest.cc b/test/compiler-unittests/common-operator-unittest.cc index f034127f9..79a34df2a 100644 --- a/test/compiler-unittests/common-operator-unittest.cc +++ b/test/compiler-unittests/common-operator-unittest.cc @@ -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)); diff --git a/test/compiler-unittests/compiler-unittests.h b/test/compiler-unittests/compiler-unittests.h index fef34cffd..82e957941 100644 --- a/test/compiler-unittests/compiler-unittests.h +++ b/test/compiler-unittests/compiler-unittests.h @@ -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. diff --git a/test/compiler-unittests/graph-unittest.cc b/test/compiler-unittests/graph-unittest.cc index e5b413c54..1d85e70f1 100644 --- a/test/compiler-unittests/graph-unittest.cc +++ b/test/compiler-unittests/graph-unittest.cc @@ -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 IsControlEffect(const Matcher& control_matcher) { } +Matcher IsValueEffect(const Matcher& value_matcher) { + return MakeMatcher(new IsUnopMatcher(IrOpcode::kValueEffect, value_matcher)); +} + + Matcher IsFinish(const Matcher& value_matcher, const Matcher& 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 diff --git a/test/compiler-unittests/graph-unittest.h b/test/compiler-unittests/graph-unittest.h index 37409198b..5bc2e7714 100644 --- a/test/compiler-unittests/graph-unittest.h +++ b/test/compiler-unittests/graph-unittest.h @@ -35,6 +35,7 @@ class GraphTest : public CommonOperatorTest { using ::testing::Matcher; + Matcher IsBranch(const Matcher& value_matcher, const Matcher& control_matcher); Matcher IsMerge(const Matcher& control0_matcher, @@ -42,6 +43,7 @@ Matcher IsMerge(const Matcher& control0_matcher, Matcher IsIfTrue(const Matcher& control_matcher); Matcher IsIfFalse(const Matcher& control_matcher); Matcher IsControlEffect(const Matcher& control_matcher); +Matcher IsValueEffect(const Matcher& value_matcher); Matcher IsFinish(const Matcher& value_matcher, const Matcher& effect_matcher); Matcher IsExternalConstant( @@ -93,6 +95,7 @@ Matcher IsWord64Equal(const Matcher& lhs_matcher, Matcher IsInt32AddWithOverflow(const Matcher& lhs_matcher, const Matcher& rhs_matcher); Matcher IsConvertInt64ToInt32(const Matcher& input_matcher); +Matcher IsChangeFloat64ToInt32(const Matcher& input_matcher); Matcher IsChangeInt32ToFloat64(const Matcher& input_matcher); } // namespace compiler