Terminate is need for non-terminating loops (NTLs) that can appear after optimizing control flow. It gathers the control and effect(s) from a NTL and connects them to end so that they are not dead-code removed.
R=mstarzinger@chromium.org
BUG=
Review URL: https://codereview.chromium.org/
651843004
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24812
ce2b1a6d-e550-0410-aec6-
3dcde31c8c00
}
+const Operator* CommonOperatorBuilder::Terminate(int effects) {
+ return new (zone()) Operator1<int>(IrOpcode::kTerminate,
+ Operator::kNoRead | Operator::kNoWrite, 0,
+ 0, "Terminate", effects);
+}
+
+
const Operator* CommonOperatorBuilder::Parameter(int index) {
return new (zone()) Operator1<int>(IrOpcode::kParameter, Operator::kPure, 1,
1, "Parameter", index);
const Operator* IfTrue();
const Operator* IfFalse();
const Operator* Throw();
+ const Operator* Terminate(int effects);
const Operator* Return();
const Operator* Start(int num_formal_parameters);
case IrOpcode::kIfFalse:
case IrOpcode::kEffectPhi:
case IrOpcode::kMerge:
+ case IrOpcode::kTerminate:
// No code needed for these graph artifacts.
return kMachNone;
case IrOpcode::kFinish:
// Opcodes for control operators.
#define INNER_CONTROL_OP_LIST(V) \
- V(Dead) \
- V(Loop) \
- V(Branch) \
- V(IfTrue) \
- V(IfFalse) \
- V(Merge) \
- V(Return) \
+ V(Dead) \
+ V(Loop) \
+ V(Branch) \
+ V(IfTrue) \
+ V(IfFalse) \
+ V(Merge) \
+ V(Return) \
+ V(Terminate) \
V(Throw)
#define CONTROL_OP_LIST(V) \
inline int OperatorProperties::GetEffectInputCount(const Operator* op) {
if (op->opcode() == IrOpcode::kEffectPhi ||
- op->opcode() == IrOpcode::kFinish) {
+ op->opcode() == IrOpcode::kFinish ||
+ op->opcode() == IrOpcode::kTerminate) {
return OpParameter<int>(op);
}
if (op->HasProperty(Operator::kNoRead) && op->HasProperty(Operator::kNoWrite))
inline bool OperatorProperties::HasEffectOutput(const Operator* op) {
return op->opcode() == IrOpcode::kStart ||
op->opcode() == IrOpcode::kValueEffect ||
- (op->opcode() != IrOpcode::kFinish && GetEffectInputCount(op) > 0);
+ (op->opcode() != IrOpcode::kFinish &&
+ op->opcode() != IrOpcode::kTerminate && GetEffectInputCount(op) > 0);
}
inline bool OperatorProperties::HasControlOutput(const Operator* op) {
// Type is empty.
CheckNotTyped(node);
break;
+ case IrOpcode::kTerminate:
+ // Type is empty.
+ CheckNotTyped(node);
+ CHECK_EQ(1, control_count);
+ CHECK_EQ(input_count, 1 + effect_count);
+ break;
// Common operators
// ----------------
CHECK(!schedule->block(f)->deferred());
}
+
+TEST(ScheduleTerminate) {
+ HandleAndZoneScope scope;
+ Graph graph(scope.main_zone());
+ CommonOperatorBuilder common(scope.main_zone());
+
+ Node* start = graph.NewNode(common.Start(1));
+ graph.SetStart(start);
+
+ Node* loop = graph.NewNode(common.Loop(2), start, start);
+ loop->ReplaceInput(1, loop); // self loop, NTL.
+
+ Node* effect = graph.NewNode(common.EffectPhi(1), start, loop);
+ effect->ReplaceInput(0, effect);
+
+ Node* terminate = graph.NewNode(common.Terminate(1), effect, loop);
+ Node* end = graph.NewNode(common.End(), terminate);
+
+ graph.SetEnd(end);
+
+ Schedule* schedule = ComputeAndVerifySchedule(5, &graph);
+ BasicBlock* block = schedule->block(loop);
+ CHECK_NE(NULL, loop);
+ CHECK_EQ(block, schedule->block(effect));
+ CHECK_GE(block->rpo_number(), 0);
+}
+
#endif