Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* number = graph()->NewNode(machine()->ChangeInt32ToFloat64(), val);
- // TODO(bmeurer): Inline allocation if possible.
const Runtime::Function* fn =
Runtime::FunctionForId(Runtime::kAllocateHeapNumber);
DCHECK_EQ(0, fn->nargs);
Node* heap_number = graph()->NewNode(
common()->Call(desc), jsgraph()->CEntryStubConstant(),
jsgraph()->ExternalConstant(ExternalReference(fn, isolate())),
- jsgraph()->ZeroConstant(), context, effect, if_true);
-
+ jsgraph()->Int32Constant(fn->nargs), context, effect, if_true);
Node* store = graph()->NewNode(
machine()->Store(kMachFloat64, kNoWriteBarrier), heap_number,
- HeapNumberValueIndexConstant(), number, effect, heap_number);
+ HeapNumberValueIndexConstant(), number, heap_number, if_true);
+ Node* finish = graph()->NewNode(common()->Finish(1), heap_number, store);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* smi = graph()->NewNode(common()->Projection(0), add);
- Node* merge = graph()->NewNode(common()->Merge(2), store, if_false);
- Node* phi = graph()->NewNode(common()->Phi(2), heap_number, smi, merge);
+ Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+ Node* phi = graph()->NewNode(common()->Phi(2), finish, smi, merge);
return Replace(phi);
}
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(), if_true);
+ Node* load = graph()->NewNode(
+ machine()->Load(kMachFloat64), val, HeapNumberValueIndexConstant(),
+ graph()->NewNode(common()->ControlEffect(), if_true));
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* integer =
return new (zone_) Operator1<int>(IrOpcode::kEffectPhi, Operator::kPure, 0,
0, "EffectPhi", arguments);
}
+ Operator* ControlEffect() {
+ return new (zone_) SimpleOperator(IrOpcode::kControlEffect, Operator::kPure,
+ 0, 0, "ControlEffect");
+ }
+ Operator* Finish(int arguments) {
+ DCHECK(arguments > 0); // Disallow empty finishes.
+ return new (zone_) Operator1<int>(IrOpcode::kFinish, Operator::kPure, 1, 1,
+ "Finish", arguments);
+ }
Operator* StateValues(int arguments) {
return new (zone_) Operator1<int>(IrOpcode::kStateValues, Operator::kPure,
arguments, 1, "StateValues", arguments);
#define INNER_OP_LIST(V) \
V(Phi) \
V(EffectPhi) \
+ V(ControlEffect) \
+ V(Finish) \
V(FrameState) \
V(StateValues) \
V(Call) \
}
inline int OperatorProperties::GetEffectInputCount(Operator* op) {
- if (op->opcode() == IrOpcode::kEffectPhi) {
+ if (op->opcode() == IrOpcode::kEffectPhi ||
+ op->opcode() == IrOpcode::kFinish) {
return static_cast<Operator1<int>*>(op)->parameter();
}
if (op->HasProperty(Operator::kNoRead) && op->HasProperty(Operator::kNoWrite))
switch (op->opcode()) {
case IrOpcode::kPhi:
case IrOpcode::kEffectPhi:
+ case IrOpcode::kControlEffect:
return 1;
#define OPCODE_CASE(x) case IrOpcode::k##x:
CONTROL_OP_LIST(OPCODE_CASE)
}
inline bool OperatorProperties::HasEffectOutput(Operator* op) {
- return op->opcode() == IrOpcode::kStart || GetEffectInputCount(op) > 0;
+ return op->opcode() == IrOpcode::kStart ||
+ op->opcode() == IrOpcode::kControlEffect ||
+ (op->opcode() != IrOpcode::kFinish && GetEffectInputCount(op) > 0);
}
inline bool OperatorProperties::HasControlOutput(Operator* op) {
}
+Bounds Typer::Visitor::TypeControlEffect(Node* node) {
+ return Bounds(Type::None(zone()));
+}
+
+
+Bounds Typer::Visitor::TypeFinish(Node* node) { return OperandType(node, 0); }
+
+
Bounds Typer::Visitor::TypeFrameState(Node* node) {
return Bounds(Type::None(zone()));
}
ASSERT_TRUE(reduction.Changed());
Node* phi = reduction.replacement();
- ASSERT_EQ(IrOpcode::kPhi, phi->opcode());
-
- Node* smi = NodeProperties::GetValueInput(phi, 1);
- ASSERT_THAT(smi, IsProjection(0, IsInt32AddWithOverflow(val, val)));
-
- Node* heap_number = NodeProperties::GetValueInput(phi, 0);
- ASSERT_EQ(IrOpcode::kCall, heap_number->opcode());
-
- Node* merge = NodeProperties::GetControlInput(phi);
- ASSERT_EQ(IrOpcode::kMerge, merge->opcode());
-
+ Capture<Node*> add, branch, heap_number, if_true;
const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag;
- EXPECT_THAT(NodeProperties::GetControlInput(merge, 0),
- IsStore(kMachFloat64, kNoWriteBarrier, heap_number,
+ 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), _, heap_number));
-
- Node* if_true = NodeProperties::GetControlInput(heap_number);
- ASSERT_EQ(IrOpcode::kIfTrue, if_true->opcode());
-
- Node* if_false = NodeProperties::GetControlInput(merge, 1);
- ASSERT_EQ(IrOpcode::kIfFalse, if_false->opcode());
-
- Node* branch = NodeProperties::GetControlInput(if_true);
- EXPECT_EQ(branch, NodeProperties::GetControlInput(if_false));
- EXPECT_THAT(branch,
- IsBranch(IsProjection(1, IsInt32AddWithOverflow(val, val)),
- graph()->start()));
+ 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()))))));
}
kSmiTagSize + SmiTagging<kPointerSize>::kSmiShiftSize;
const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag;
Node* phi = reduction.replacement();
- Capture<Node*> branch;
+ Capture<Node*> branch, if_true;
EXPECT_THAT(
phi,
- IsPhi(IsLoad(kMachFloat64, val, IsInt32Constant(kValueOffset), _),
- IsChangeInt32ToFloat64(
- IsWord32Sar(val, IsInt32Constant(kShiftAmount))),
- IsMerge(IsIfTrue(AllOf(
+ IsPhi(
+ IsLoad(kMachFloat64, val, IsInt32Constant(kValueOffset),
+ IsControlEffect(CaptureEq(&if_true))),
+ IsChangeInt32ToFloat64(
+ IsWord32Sar(val, IsInt32Constant(kShiftAmount))),
+ IsMerge(
+ AllOf(CaptureEq(&if_true),
+ IsIfTrue(AllOf(
CaptureEq(&branch),
IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
- graph()->start()))),
- IsIfFalse(CaptureEq(&branch)))));
+ graph()->start())))),
+ IsIfFalse(CaptureEq(&branch)))));
}
kSmiTagSize + SmiTagging<kPointerSize>::kSmiShiftSize;
const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag;
Node* phi = reduction.replacement();
- Capture<Node*> branch;
+ Capture<Node*> branch, if_true;
EXPECT_THAT(
phi,
- IsPhi(IsLoad(kMachFloat64, val, IsInt32Constant(kValueOffset), _),
- IsChangeInt32ToFloat64(IsConvertInt64ToInt32(
- IsWord64Sar(val, IsInt32Constant(kShiftAmount)))),
- IsMerge(IsIfTrue(AllOf(
+ IsPhi(
+ IsLoad(kMachFloat64, val, IsInt32Constant(kValueOffset),
+ IsControlEffect(CaptureEq(&if_true))),
+ IsChangeInt32ToFloat64(IsConvertInt64ToInt32(
+ IsWord64Sar(val, IsInt32Constant(kShiftAmount)))),
+ IsMerge(
+ AllOf(CaptureEq(&if_true),
+ IsIfTrue(AllOf(
CaptureEq(&branch),
IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
- graph()->start()))),
- IsIfFalse(CaptureEq(&branch)))));
+ graph()->start())))),
+ IsIfFalse(CaptureEq(&branch)))));
}
} // namespace compiler
CommonOperatorTest::~CommonOperatorTest() {}
+
+TEST_F(CommonOperatorTest, ControlEffect) {
+ Operator* op = common()->ControlEffect();
+ EXPECT_EQ(1, OperatorProperties::GetControlInputCount(op));
+ EXPECT_EQ(1, 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));
+ EXPECT_EQ(arguments, OperatorProperties::GetEffectInputCount(op));
+ EXPECT_EQ(arguments + 1, OperatorProperties::GetTotalInputCount(op));
+ EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
+ EXPECT_EQ(0, OperatorProperties::GetEffectOutputCount(op));
+ EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
+ }
+}
+
} // namespace compiler
} // namespace internal
} // namespace v8
const PrintableUnique<T>& value) {
return os << value.string();
}
+inline std::ostream& operator<<(std::ostream& os,
+ const ExternalReference& value) {
+ OStringStream ost;
+ compiler::StaticParameterTraits<ExternalReference>::PrintTo(ost, value);
+ return os << ost.c_str();
+}
namespace compiler {
return false;
}
if (node->opcode() != opcode_) {
- *listener << "whose opcode is " << IrOpcode::Mnemonic(node->opcode());
+ *listener << "whose opcode is " << IrOpcode::Mnemonic(node->opcode())
+ << " but should have been " << IrOpcode::Mnemonic(opcode_);
return false;
}
return true;
};
-class IsIfTrueMatcher V8_FINAL : public NodeMatcher {
+class IsControl1Matcher V8_FINAL : public NodeMatcher {
public:
- explicit IsIfTrueMatcher(const Matcher<Node*>& control_matcher)
- : NodeMatcher(IrOpcode::kIfTrue), control_matcher_(control_matcher) {}
+ IsControl1Matcher(IrOpcode::Value opcode,
+ const Matcher<Node*>& control_matcher)
+ : NodeMatcher(opcode), control_matcher_(control_matcher) {}
virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
NodeMatcher::DescribeTo(os);
};
-class IsIfFalseMatcher V8_FINAL : public NodeMatcher {
+class IsFinishMatcher V8_FINAL : public NodeMatcher {
public:
- explicit IsIfFalseMatcher(const Matcher<Node*>& control_matcher)
- : NodeMatcher(IrOpcode::kIfFalse), control_matcher_(control_matcher) {}
+ IsFinishMatcher(const Matcher<Node*>& value_matcher,
+ const Matcher<Node*>& effect_matcher)
+ : NodeMatcher(IrOpcode::kFinish),
+ value_matcher_(value_matcher),
+ effect_matcher_(effect_matcher) {}
virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
NodeMatcher::DescribeTo(os);
- *os << " whose control (";
- control_matcher_.DescribeTo(os);
+ *os << " whose value (";
+ value_matcher_.DescribeTo(os);
+ *os << ") and effect (";
+ effect_matcher_.DescribeTo(os);
*os << ")";
}
virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
V8_OVERRIDE {
return (NodeMatcher::MatchAndExplain(node, listener) &&
- PrintMatchAndExplain(NodeProperties::GetControlInput(node),
- "control", control_matcher_, listener));
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+ "value", value_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+ effect_matcher_, listener));
}
private:
- const Matcher<Node*> control_matcher_;
+ const Matcher<Node*> value_matcher_;
+ const Matcher<Node*> effect_matcher_;
};
};
+class IsCallMatcher V8_FINAL : public NodeMatcher {
+ public:
+ IsCallMatcher(const Matcher<CallDescriptor*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher,
+ const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher,
+ const Matcher<Node*>& value3_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher)
+ : NodeMatcher(IrOpcode::kCall),
+ descriptor_matcher_(descriptor_matcher),
+ value0_matcher_(value0_matcher),
+ value1_matcher_(value1_matcher),
+ value2_matcher_(value2_matcher),
+ value3_matcher_(value3_matcher),
+ effect_matcher_(effect_matcher),
+ control_matcher_(control_matcher) {}
+
+ virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
+ NodeMatcher::DescribeTo(os);
+ *os << " whose value0 (";
+ value0_matcher_.DescribeTo(os);
+ *os << ") and value1 (";
+ value1_matcher_.DescribeTo(os);
+ *os << ") and value2 (";
+ value2_matcher_.DescribeTo(os);
+ *os << ") and value3 (";
+ value3_matcher_.DescribeTo(os);
+ *os << ") and effect (";
+ effect_matcher_.DescribeTo(os);
+ *os << ") and control (";
+ control_matcher_.DescribeTo(os);
+ *os << ")";
+ }
+
+ virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
+ V8_OVERRIDE {
+ return (NodeMatcher::MatchAndExplain(node, listener) &&
+ PrintMatchAndExplain(OpParameter<CallDescriptor*>(node),
+ "descriptor", descriptor_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+ "value0", value0_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+ "value1", value1_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
+ "value2", value2_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 3),
+ "value3", value3_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+ effect_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+ "control", control_matcher_, listener));
+ }
+
+ private:
+ const Matcher<CallDescriptor*> descriptor_matcher_;
+ const Matcher<Node*> value0_matcher_;
+ const Matcher<Node*> value1_matcher_;
+ const Matcher<Node*> value2_matcher_;
+ const Matcher<Node*> value3_matcher_;
+ const Matcher<Node*> effect_matcher_;
+ const Matcher<Node*> control_matcher_;
+};
+
+
class IsLoadMatcher V8_FINAL : public NodeMatcher {
public:
IsLoadMatcher(const Matcher<MachineType>& type_matcher,
Matcher<Node*> IsIfTrue(const Matcher<Node*>& control_matcher) {
- return MakeMatcher(new IsIfTrueMatcher(control_matcher));
+ return MakeMatcher(new IsControl1Matcher(IrOpcode::kIfTrue, control_matcher));
}
Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher) {
- return MakeMatcher(new IsIfFalseMatcher(control_matcher));
+ return MakeMatcher(
+ new IsControl1Matcher(IrOpcode::kIfFalse, control_matcher));
}
-Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher) {
+Matcher<Node*> IsControlEffect(const Matcher<Node*>& control_matcher) {
return MakeMatcher(
- new IsConstantMatcher<int32_t>(IrOpcode::kInt32Constant, value_matcher));
+ new IsControl1Matcher(IrOpcode::kControlEffect, control_matcher));
+}
+
+
+Matcher<Node*> IsFinish(const Matcher<Node*>& value_matcher,
+ const Matcher<Node*>& effect_matcher) {
+ return MakeMatcher(new IsFinishMatcher(value_matcher, effect_matcher));
+}
+
+
+Matcher<Node*> IsExternalConstant(
+ const Matcher<ExternalReference>& value_matcher) {
+ return MakeMatcher(new IsConstantMatcher<ExternalReference>(
+ IrOpcode::kExternalConstant, value_matcher));
}
}
+Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher) {
+ return MakeMatcher(
+ new IsConstantMatcher<int32_t>(IrOpcode::kInt32Constant, value_matcher));
+}
+
+
+Matcher<Node*> IsNumberConstant(const Matcher<double>& value_matcher) {
+ return MakeMatcher(
+ new IsConstantMatcher<double>(IrOpcode::kNumberConstant, value_matcher));
+}
+
+
Matcher<Node*> IsPhi(const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& merge_matcher) {
}
+Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher,
+ const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher,
+ const Matcher<Node*>& value3_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher) {
+ return MakeMatcher(new IsCallMatcher(
+ descriptor_matcher, value0_matcher, value1_matcher, value2_matcher,
+ value3_matcher, effect_matcher, control_matcher));
+}
+
+
Matcher<Node*> IsLoad(const Matcher<MachineType>& type_matcher,
const Matcher<Node*>& base_matcher,
const Matcher<Node*>& index_matcher,
const Matcher<Node*>& control1_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*> IsFinish(const Matcher<Node*>& value_matcher,
+ const Matcher<Node*>& effect_matcher);
+Matcher<Node*> IsExternalConstant(
+ const Matcher<ExternalReference>& value_matcher);
Matcher<Node*> IsHeapConstant(
const Matcher<PrintableUnique<HeapObject> >& value_matcher);
Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher);
+Matcher<Node*> IsNumberConstant(const Matcher<double>& value_matcher);
Matcher<Node*> IsPhi(const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& merge_matcher);
Matcher<Node*> IsProjection(const Matcher<int32_t>& index_matcher,
const Matcher<Node*>& base_matcher);
+Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher,
+ const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher,
+ const Matcher<Node*>& value3_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher);
Matcher<Node*> IsLoad(const Matcher<MachineType>& type_matcher,
const Matcher<Node*>& base_matcher,