Begin changing Hydrogen branch instructions.

Rename HBranch (the instruction that coerces an arbitrary HValue to
control flow) to HTest to free up the term Branch to refer to any
control instruction with two successors.

Change the virtual FirstSuccessor and SecondSuccessor functions on
control instructions to a pair of data members.

Review URL: http://codereview.chromium.org/6366002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6417 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kmillikin@chromium.org 2011-01-20 12:56:34 +00:00
parent 89e74000a0
commit 3d15b43393
9 changed files with 131 additions and 157 deletions

View File

@ -882,8 +882,8 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
if (FLAG_stress_environments && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr);
}
if (current->IsBranch()) {
instr->set_hydrogen_value(HBranch::cast(current)->value());
if (current->IsTest()) {
instr->set_hydrogen_value(HTest::cast(current)->value());
} else {
instr->set_hydrogen_value(current);
}
@ -937,7 +937,7 @@ LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
}
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
LInstruction* LChunkBuilder::DoTest(HTest* instr) {
HValue* v = instr->value();
HBasicBlock* first = instr->FirstSuccessor();
HBasicBlock* second = instr->SecondSuccessor();
@ -1059,8 +1059,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
}
LInstruction* LChunkBuilder::DoCompareMapAndBranch(
HCompareMapAndBranch* instr) {
LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
LOperand* temp = TempRegister();

View File

@ -1082,17 +1082,17 @@ class LCmpMapAndBranch: public LUnaryOperation {
: LUnaryOperation(value), temp_(temp) { }
DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareMapAndBranch)
DECLARE_HYDROGEN_ACCESSOR(CompareMap)
virtual bool IsControl() const { return true; }
LOperand* temp() const { return temp_; }
Handle<Map> map() const { return hydrogen()->map(); }
int true_block_id() const {
return hydrogen()->true_destination()->block_id();
return hydrogen()->FirstSuccessor()->block_id();
}
int false_block_id() const {
return hydrogen()->false_destination()->block_id();
return hydrogen()->SecondSuccessor()->block_id();
}
private:

View File

@ -570,34 +570,29 @@ void HCallConstantFunction::PrintDataTo(StringStream* stream) const {
}
void HBranch::PrintDataTo(StringStream* stream) const {
void HControlInstruction::PrintDataTo(StringStream* stream) const {
if (FirstSuccessor() != NULL) {
int first_id = FirstSuccessor()->block_id();
if (SecondSuccessor() == NULL) {
stream->Add(" B%d", first_id);
} else {
int second_id = SecondSuccessor()->block_id();
stream->Add("on ");
value()->PrintNameTo(stream);
stream->Add(" (B%d, B%d)", first_id, second_id);
stream->Add(" goto (B%d, B%d)", first_id, second_id);
}
}
}
void HCompareMapAndBranch::PrintDataTo(StringStream* stream) const {
stream->Add("on ");
void HUnaryControlInstruction::PrintDataTo(StringStream* stream) const {
value()->PrintNameTo(stream);
HControlInstruction::PrintDataTo(stream);
}
void HCompareMap::PrintDataTo(StringStream* stream) const {
value()->PrintNameTo(stream);
stream->Add(" (%p)", *map());
}
void HGoto::PrintDataTo(StringStream* stream) const {
stream->Add("B%d", FirstSuccessor()->block_id());
}
void HReturn::PrintDataTo(StringStream* stream) const {
value()->PrintNameTo(stream);
}
void HThrow::PrintDataTo(StringStream* stream) const {
value()->PrintNameTo(stream);
HControlInstruction::PrintDataTo(stream);
}

View File

@ -1,4 +1,4 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -99,9 +99,9 @@ class LChunkBuilder;
// HDeoptimize
// HGoto
// HUnaryControlInstruction
// HBranch
// HCompareMapAndBranch
// HCompareMap
// HReturn
// HTest
// HThrow
// HEnterInlined
// HFunctionLiteral
@ -183,7 +183,6 @@ class LChunkBuilder;
V(BitXor) \
V(BlockEntry) \
V(BoundsCheck) \
V(Branch) \
V(CallConstantFunction) \
V(CallFunction) \
V(CallGlobal) \
@ -202,7 +201,7 @@ class LChunkBuilder;
V(CheckSmi) \
V(Compare) \
V(CompareJSObjectEq) \
V(CompareMapAndBranch) \
V(CompareMap) \
V(Constant) \
V(DeleteProperty) \
V(Deoptimize) \
@ -253,6 +252,7 @@ class LChunkBuilder;
V(StringCharCodeAt) \
V(StringLength) \
V(Sub) \
V(Test) \
V(Throw) \
V(Typeof) \
V(TypeofIs) \
@ -815,44 +815,55 @@ class HBlockEntry: public HInstruction {
class HControlInstruction: public HInstruction {
public:
virtual HBasicBlock* FirstSuccessor() const { return NULL; }
virtual HBasicBlock* SecondSuccessor() const { return NULL; }
HControlInstruction(HBasicBlock* first, HBasicBlock* second)
: first_successor_(first), second_successor_(second) {
}
HBasicBlock* FirstSuccessor() const { return first_successor_; }
HBasicBlock* SecondSuccessor() const { return second_successor_; }
virtual void PrintDataTo(StringStream* stream) const;
DECLARE_INSTRUCTION(ControlInstruction)
private:
HBasicBlock* first_successor_;
HBasicBlock* second_successor_;
};
class HDeoptimize: public HControlInstruction {
public:
HDeoptimize() : HControlInstruction(NULL, NULL) { }
DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
};
class HGoto: public HControlInstruction {
public:
explicit HGoto(HBasicBlock* destination)
: destination_(destination),
include_stack_check_(false) {}
explicit HGoto(HBasicBlock* target)
: HControlInstruction(target, NULL), include_stack_check_(false) {
}
virtual HBasicBlock* FirstSuccessor() const { return destination_; }
void set_include_stack_check(bool include_stack_check) {
include_stack_check_ = include_stack_check;
}
bool include_stack_check() const { return include_stack_check_; }
virtual void PrintDataTo(StringStream* stream) const;
DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
private:
HBasicBlock* destination_;
bool include_stack_check_;
};
class HUnaryControlInstruction: public HControlInstruction {
public:
explicit HUnaryControlInstruction(HValue* value) {
explicit HUnaryControlInstruction(HValue* value,
HBasicBlock* true_target,
HBasicBlock* false_target)
: HControlInstruction(true_target, false_target) {
SetOperandAt(0, value);
}
@ -860,6 +871,8 @@ class HUnaryControlInstruction: public HControlInstruction {
return Representation::Tagged();
}
virtual void PrintDataTo(StringStream* stream) const;
HValue* value() const { return OperandAt(0); }
virtual int OperandCount() const { return 1; }
virtual HValue* OperandAt(int index) const { return operands_[index]; }
@ -876,73 +889,50 @@ class HUnaryControlInstruction: public HControlInstruction {
};
class HBranch: public HUnaryControlInstruction {
class HTest: public HUnaryControlInstruction {
public:
HBranch(HBasicBlock* true_destination,
HBasicBlock* false_destination,
HValue* boolean_value)
: HUnaryControlInstruction(boolean_value),
true_destination_(true_destination),
false_destination_(false_destination) {
ASSERT(true_destination != NULL && false_destination != NULL);
HTest(HValue* value, HBasicBlock* true_target, HBasicBlock* false_target)
: HUnaryControlInstruction(value, true_target, false_target) {
ASSERT(true_target != NULL && false_target != NULL);
}
virtual Representation RequiredInputRepresentation(int index) const {
return Representation::None();
}
virtual HBasicBlock* FirstSuccessor() const { return true_destination_; }
virtual HBasicBlock* SecondSuccessor() const { return false_destination_; }
virtual void PrintDataTo(StringStream* stream) const;
DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
private:
HBasicBlock* true_destination_;
HBasicBlock* false_destination_;
DECLARE_CONCRETE_INSTRUCTION(Test, "test")
};
class HCompareMapAndBranch: public HUnaryControlInstruction {
class HCompareMap: public HUnaryControlInstruction {
public:
HCompareMapAndBranch(HValue* result,
HCompareMap(HValue* value,
Handle<Map> map,
HBasicBlock* true_destination,
HBasicBlock* false_destination)
: HUnaryControlInstruction(result),
map_(map),
true_destination_(true_destination),
false_destination_(false_destination) {
ASSERT(true_destination != NULL);
ASSERT(false_destination != NULL);
HBasicBlock* true_target,
HBasicBlock* false_target)
: HUnaryControlInstruction(value, true_target, false_target),
map_(map) {
ASSERT(true_target != NULL);
ASSERT(false_target != NULL);
ASSERT(!map.is_null());
}
virtual HBasicBlock* FirstSuccessor() const { return true_destination_; }
virtual HBasicBlock* SecondSuccessor() const { return false_destination_; }
HBasicBlock* true_destination() const { return true_destination_; }
HBasicBlock* false_destination() const { return false_destination_; }
virtual void PrintDataTo(StringStream* stream) const;
Handle<Map> map() const { return map_; }
DECLARE_CONCRETE_INSTRUCTION(CompareMapAndBranch, "compare_map_and_branch")
DECLARE_CONCRETE_INSTRUCTION(CompareMap, "compare_map")
private:
Handle<Map> map_;
HBasicBlock* true_destination_;
HBasicBlock* false_destination_;
};
class HReturn: public HUnaryControlInstruction {
public:
explicit HReturn(HValue* result) : HUnaryControlInstruction(result) { }
virtual void PrintDataTo(StringStream* stream) const;
explicit HReturn(HValue* value)
: HUnaryControlInstruction(value, NULL, NULL) {
}
DECLARE_CONCRETE_INSTRUCTION(Return, "return")
};
@ -950,9 +940,8 @@ class HReturn: public HUnaryControlInstruction {
class HThrow: public HUnaryControlInstruction {
public:
explicit HThrow(HValue* value) : HUnaryControlInstruction(value) { }
virtual void PrintDataTo(StringStream* stream) const;
explicit HThrow(HValue* value)
: HUnaryControlInstruction(value, NULL, NULL) { }
DECLARE_CONCRETE_INSTRUCTION(Throw, "throw")
};

View File

@ -505,19 +505,15 @@ HConstant* HGraph::GetConstantFalse() {
void HSubgraph::AppendOptional(HSubgraph* graph,
bool on_true_branch,
HValue* boolean_value) {
HValue* value) {
ASSERT(HasExit() && graph->HasExit());
HBasicBlock* other_block = graph_->CreateBasicBlock();
HBasicBlock* join_block = graph_->CreateBasicBlock();
HBasicBlock* true_branch = other_block;
HBasicBlock* false_branch = graph->entry_block();
if (on_true_branch) {
true_branch = graph->entry_block();
false_branch = other_block;
}
exit_block_->Finish(new HBranch(true_branch, false_branch, boolean_value));
HTest* test = on_true_branch
? new HTest(value, graph->entry_block(), other_block)
: new HTest(value, other_block, graph->entry_block());
exit_block_->Finish(test);
other_block->Goto(join_block);
graph->exit_block()->Goto(join_block);
exit_block_ = join_block;
@ -935,7 +931,7 @@ class HRangeAnalysis BASE_EMBEDDED {
private:
void TraceRange(const char* msg, ...);
void Analyze(HBasicBlock* block);
void InferControlFlowRange(HBranch* branch, HBasicBlock* dest);
void InferControlFlowRange(HTest* test, HBasicBlock* dest);
void InferControlFlowRange(Token::Value op, HValue* value, HValue* other);
void InferPhiRange(HPhi* phi);
void InferRange(HValue* value);
@ -971,8 +967,8 @@ void HRangeAnalysis::Analyze(HBasicBlock* block) {
// Infer range based on control flow.
if (block->predecessors()->length() == 1) {
HBasicBlock* pred = block->predecessors()->first();
if (pred->end()->IsBranch()) {
InferControlFlowRange(HBranch::cast(pred->end()), block);
if (pred->end()->IsTest()) {
InferControlFlowRange(HTest::cast(pred->end()), block);
}
}
@ -998,14 +994,12 @@ void HRangeAnalysis::Analyze(HBasicBlock* block) {
}
void HRangeAnalysis::InferControlFlowRange(HBranch* branch, HBasicBlock* dest) {
ASSERT(branch->FirstSuccessor() == dest || branch->SecondSuccessor() == dest);
ASSERT(branch->FirstSuccessor() != dest || branch->SecondSuccessor() != dest);
if (branch->value()->IsCompare()) {
HCompare* compare = HCompare::cast(branch->value());
void HRangeAnalysis::InferControlFlowRange(HTest* test, HBasicBlock* dest) {
ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest));
if (test->value()->IsCompare()) {
HCompare* compare = HCompare::cast(test->value());
Token::Value op = compare->token();
if (branch->SecondSuccessor() == dest) {
if (test->SecondSuccessor() == dest) {
op = Token::NegateCompareOp(op);
}
Token::Value inverted_op = Token::InvertCompareOp(op);
@ -2068,8 +2062,8 @@ void TestContext::BuildBranch(HValue* value) {
HGraphBuilder* builder = owner();
HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
HBranch* branch = new HBranch(empty_true, empty_false, value);
builder->CurrentBlock()->Finish(branch);
HTest* test = new HTest(value, empty_true, empty_false);
builder->CurrentBlock()->Finish(test);
HValue* const no_return_value = NULL;
HBasicBlock* true_target = if_true();
@ -2597,9 +2591,9 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block()));
} else {
HBasicBlock* empty = graph()->CreateBasicBlock();
prev_graph->exit_block()->Finish(new HBranch(empty,
subgraph->entry_block(),
prev_compare_inst));
prev_graph->exit_block()->Finish(new HTest(prev_compare_inst,
empty,
subgraph->entry_block()));
}
// Build instructions for current subgraph.
@ -2618,9 +2612,9 @@ void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
if (prev_graph != current_subgraph_) {
last_false_block = graph()->CreateBasicBlock();
HBasicBlock* empty = graph()->CreateBasicBlock();
prev_graph->exit_block()->Finish(new HBranch(empty,
last_false_block,
prev_compare_inst));
prev_graph->exit_block()->Finish(new HTest(prev_compare_inst,
empty,
last_false_block));
}
// If we have a non-smi compare clause, we deoptimize after trying
@ -2703,8 +2697,8 @@ void HSubgraph::PreProcessOsrEntry(IterationStatement* statement) {
HBasicBlock* non_osr_entry = graph()->CreateBasicBlock();
HBasicBlock* osr_entry = graph()->CreateBasicBlock();
HValue* true_value = graph()->GetConstantTrue();
HBranch* branch = new HBranch(non_osr_entry, osr_entry, true_value);
exit_block()->Finish(branch);
HTest* test = new HTest(true_value, non_osr_entry, osr_entry);
exit_block()->Finish(test);
HBasicBlock* loop_predecessor = graph()->CreateBasicBlock();
non_osr_entry->Goto(loop_predecessor);
@ -3106,11 +3100,11 @@ HBasicBlock* HGraphBuilder::BuildTypeSwitch(ZoneMapList* maps,
(i == (maps->length() - 1))
? subgraphs->last()
: map_compare_subgraphs.last();
current_subgraph_->exit_block()->Finish(
new HCompareMapAndBranch(receiver,
HCompareMap* compare = new HCompareMap(receiver,
maps->at(i),
subgraphs->at(i)->entry_block(),
else_subgraph->entry_block()));
else_subgraph->entry_block());
current_subgraph_->exit_block()->Finish(compare);
map_compare_subgraphs.Add(subgraph);
}
@ -3118,11 +3112,11 @@ HBasicBlock* HGraphBuilder::BuildTypeSwitch(ZoneMapList* maps,
AddInstruction(new HCheckNonSmi(receiver));
HSubgraph* else_subgraph =
(maps->length() == 1) ? subgraphs->at(1) : map_compare_subgraphs.last();
current_subgraph_->exit_block()->Finish(
new HCompareMapAndBranch(receiver,
HCompareMap* compare = new HCompareMap(receiver,
Handle<Map>(maps->first()),
subgraphs->first()->entry_block(),
else_subgraph->entry_block()));
else_subgraph->entry_block());
current_subgraph_->exit_block()->Finish(compare);
// Join all the call subgraphs in a new basic block and make
// this basic block the current basic block.
@ -4076,9 +4070,8 @@ bool HGraphBuilder::TryInline(Call* expr) {
// TODO(3168478): refactor to avoid this.
HBasicBlock* empty_true = graph()->CreateBasicBlock();
HBasicBlock* empty_false = graph()->CreateBasicBlock();
HBranch* branch =
new HBranch(empty_true, empty_false, return_value);
body->exit_block()->Finish(branch);
HTest* test = new HTest(return_value, empty_true, empty_false);
body->exit_block()->Finish(test);
HValue* const no_return_value = NULL;
empty_true->AddLeaveInlined(no_return_value, test_context->if_true());

View File

@ -920,15 +920,15 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
if (FLAG_stress_environments && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr);
}
if (current->IsBranch() && !instr->IsGoto()) {
// TODO(fschneider): Handle branch instructions uniformly like
if (current->IsTest() && !instr->IsGoto()) {
// TODO(fschneider): Handle test instructions uniformly like
// other instructions. This requires us to generate the right
// branch instruction already at the HIR level.
ASSERT(instr->IsControl());
HBranch* branch = HBranch::cast(current);
instr->set_hydrogen_value(branch->value());
HBasicBlock* first = branch->FirstSuccessor();
HBasicBlock* second = branch->SecondSuccessor();
HTest* test = HTest::cast(current);
instr->set_hydrogen_value(test->value());
HBasicBlock* first = test->FirstSuccessor();
HBasicBlock* second = test->SecondSuccessor();
ASSERT(first != NULL && second != NULL);
instr->SetBranchTargets(first->block_id(), second->block_id());
} else {
@ -985,7 +985,7 @@ LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
}
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
LInstruction* LChunkBuilder::DoTest(HTest* instr) {
HValue* v = instr->value();
if (v->EmitAtUses()) {
if (v->IsClassOfTest()) {
@ -1087,8 +1087,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
}
LInstruction* LChunkBuilder::DoCompareMapAndBranch(
HCompareMapAndBranch* instr) {
LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
return new LCmpMapAndBranch(value);

View File

@ -1049,16 +1049,16 @@ class LCmpMapAndBranch: public LTemplateInstruction<0, 1> {
}
DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareMapAndBranch)
DECLARE_HYDROGEN_ACCESSOR(CompareMap)
virtual bool IsControl() const { return true; }
Handle<Map> map() const { return hydrogen()->map(); }
int true_block_id() const {
return hydrogen()->true_destination()->block_id();
return hydrogen()->FirstSuccessor()->block_id();
}
int false_block_id() const {
return hydrogen()->false_destination()->block_id();
return hydrogen()->SecondSuccessor()->block_id();
}
};

View File

@ -847,15 +847,15 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
if (FLAG_stress_environments && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr);
}
if (current->IsBranch() && !instr->IsGoto()) {
// TODO(fschneider): Handle branch instructions uniformly like
if (current->IsTest() && !instr->IsGoto()) {
// TODO(fschneider): Handle test instructions uniformly like
// other instructions. This requires us to generate the right
// branch instruction already at the HIR level.
ASSERT(instr->IsControl());
HBranch* branch = HBranch::cast(current);
instr->set_hydrogen_value(branch->value());
HBasicBlock* first = branch->FirstSuccessor();
HBasicBlock* second = branch->SecondSuccessor();
HTest* test = HTest::cast(current);
instr->set_hydrogen_value(test->value());
HBasicBlock* first = test->FirstSuccessor();
HBasicBlock* second = test->SecondSuccessor();
ASSERT(first != NULL && second != NULL);
instr->SetBranchTargets(first->block_id(), second->block_id());
} else {
@ -912,7 +912,7 @@ LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
}
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
LInstruction* LChunkBuilder::DoTest(HTest* instr) {
HValue* v = instr->value();
if (v->EmitAtUses()) {
if (v->IsClassOfTest()) {
@ -1013,9 +1013,8 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
}
LInstruction* LChunkBuilder::DoCompareMapAndBranch(
HCompareMapAndBranch* instr) {
Abort("Unimplemented: %s", "DoCompareMapAndBranch");
LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
Abort("Unimplemented: %s", "DoCompareMap");
return NULL;
}

View File

@ -1046,16 +1046,16 @@ class LCmpMapAndBranch: public LTemplateInstruction<0, 1> {
}
DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch")
DECLARE_HYDROGEN_ACCESSOR(CompareMapAndBranch)
DECLARE_HYDROGEN_ACCESSOR(CompareMap)
virtual bool IsControl() const { return true; }
Handle<Map> map() const { return hydrogen()->map(); }
int true_block_id() const {
return hydrogen()->true_destination()->block_id();
return hydrogen()->FirstSuccessor()->block_id();
}
int false_block_id() const {
return hydrogen()->false_destination()->block_id();
return hydrogen()->SecondSuccessor()->block_id();
}
};