Commit 43c7345b authored by dcarney's avatar dcarney Committed by Commit bot

[turbofan] only use two gaps

BUG=

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

Cr-Commit-Position: refs/heads/master@{#26814}
parent 32bac2df
......@@ -81,6 +81,28 @@ bool ParallelMove::IsRedundant() const {
}
MoveOperands* ParallelMove::PrepareInsertAfter(MoveOperands* move) const {
auto move_ops = move_operands();
MoveOperands* replacement = nullptr;
MoveOperands* to_eliminate = nullptr;
for (auto curr = move_ops->begin(); curr != move_ops->end(); ++curr) {
if (curr->IsEliminated()) continue;
if (curr->destination()->Equals(move->source())) {
DCHECK(!replacement);
replacement = curr;
if (to_eliminate != nullptr) break;
} else if (curr->destination()->Equals(move->destination())) {
DCHECK(!to_eliminate);
to_eliminate = curr;
if (replacement != nullptr) break;
}
}
DCHECK_IMPLIES(replacement == to_eliminate, replacement == nullptr);
if (replacement != nullptr) move->set_source(replacement->source());
return to_eliminate;
}
Instruction::Instruction(InstructionCode opcode)
: opcode_(opcode),
bit_field_(OutputCountField::encode(0) | InputCountField::encode(0) |
......
......@@ -400,6 +400,12 @@ class ParallelMove FINAL : public ZoneObject {
return &move_operands_;
}
// Prepare this ParallelMove to insert move as if it happened in a subsequent
// ParallelMove. move->source() may be changed. The MoveOperand returned
// must be Eliminated and, as it points directly into move_operands_, it must
// be Eliminated before any further mutation.
MoveOperands* PrepareInsertAfter(MoveOperands* move) const;
private:
ZoneList<MoveOperands> move_operands_;
};
......@@ -596,12 +602,10 @@ std::ostream& operator<<(std::ostream& os, const PrintableInstruction& instr);
class GapInstruction : public Instruction {
public:
enum InnerPosition {
BEFORE,
START,
END,
AFTER,
FIRST_INNER_POSITION = BEFORE,
LAST_INNER_POSITION = AFTER
FIRST_INNER_POSITION = START,
LAST_INNER_POSITION = END
};
ParallelMove* GetOrCreateParallelMove(InnerPosition pos, Zone* zone) {
......@@ -640,10 +644,8 @@ class GapInstruction : public Instruction {
protected:
explicit GapInstruction(InstructionCode opcode) : Instruction(opcode) {
parallel_moves_[BEFORE] = NULL;
parallel_moves_[START] = NULL;
parallel_moves_[END] = NULL;
parallel_moves_[AFTER] = NULL;
}
private:
......
......@@ -10,33 +10,6 @@ namespace compiler {
namespace {
MoveOperands* PrepareInsertAfter(ParallelMove* left, MoveOperands* move,
Zone* zone) {
auto move_ops = left->move_operands();
MoveOperands* replacement = nullptr;
MoveOperands* to_eliminate = nullptr;
for (auto curr = move_ops->begin(); curr != move_ops->end(); ++curr) {
if (curr->IsEliminated()) continue;
if (curr->destination()->Equals(move->source())) {
DCHECK(!replacement);
replacement = curr;
if (to_eliminate != nullptr) break;
} else if (curr->destination()->Equals(move->destination())) {
DCHECK(!to_eliminate);
to_eliminate = curr;
if (replacement != nullptr) break;
}
}
DCHECK(!(replacement == to_eliminate && replacement != nullptr));
if (replacement != nullptr) {
auto new_source = InstructionOperand::New(
zone, replacement->source()->kind(), replacement->source()->index());
move->set_source(new_source);
}
return to_eliminate;
}
bool GapsCanMoveOver(Instruction* instr) {
DCHECK(!instr->IsGapMoves());
return instr->IsSourcePosition() || instr->IsNop();
......@@ -90,7 +63,7 @@ void MoveOptimizer::CompressMoves(MoveOpVector* eliminated, ParallelMove* left,
// merging the two gaps.
for (auto op = move_ops->begin(); op != move_ops->end(); ++op) {
if (op->IsRedundant()) continue;
MoveOperands* to_eliminate = PrepareInsertAfter(left, op, code_zone());
auto to_eliminate = left->PrepareInsertAfter(op);
if (to_eliminate != nullptr) eliminated->push_back(to_eliminate);
}
// Eliminate dead moves. Must happen before insertion of new moves as the
......
......@@ -1415,22 +1415,6 @@ void RegisterAllocator::ResolvePhis() {
}
ParallelMove* RegisterAllocator::GetConnectingParallelMove(
LifetimePosition pos) {
int index = pos.InstructionIndex();
if (code()->IsGapAt(index)) {
auto gap = code()->GapAt(index);
return gap->GetOrCreateParallelMove(
pos.IsInstructionStart() ? GapInstruction::START : GapInstruction::END,
code_zone());
}
int gap_pos = pos.IsInstructionStart() ? (index - 1) : (index + 1);
return code()->GapAt(gap_pos)->GetOrCreateParallelMove(
(gap_pos < index) ? GapInstruction::AFTER : GapInstruction::START,
code_zone());
}
const InstructionBlock* RegisterAllocator::GetInstructionBlock(
LifetimePosition pos) {
return code()->GetInstructionBlock(pos.InstructionIndex());
......@@ -1438,33 +1422,74 @@ const InstructionBlock* RegisterAllocator::GetInstructionBlock(
void RegisterAllocator::ConnectRanges() {
ZoneMap<std::pair<ParallelMove*, InstructionOperand*>, InstructionOperand*>
delayed_insertion_map(local_zone());
for (auto first_range : live_ranges()) {
if (first_range == nullptr || first_range->IsChild()) continue;
auto second_range = first_range->next();
while (second_range != nullptr) {
for (auto second_range = first_range->next(); second_range != nullptr;
first_range = second_range, second_range = second_range->next()) {
auto pos = second_range->Start();
if (!second_range->IsSpilled()) {
// Add gap move if the two live ranges touch and there is no block
// boundary.
if (first_range->End().Value() == pos.Value()) {
bool should_insert = true;
if (IsBlockBoundary(pos)) {
should_insert =
CanEagerlyResolveControlFlow(GetInstructionBlock(pos));
}
if (should_insert) {
auto move = GetConnectingParallelMove(pos);
auto prev_operand =
first_range->GetAssignedOperand(operand_cache());
auto cur_operand =
second_range->GetAssignedOperand(operand_cache());
move->AddMove(prev_operand, cur_operand, code_zone());
}
}
// Add gap move if the two live ranges touch and there is no block
// boundary.
if (second_range->IsSpilled()) continue;
if (first_range->End().Value() != pos.Value()) continue;
if (IsBlockBoundary(pos) &&
!CanEagerlyResolveControlFlow(GetInstructionBlock(pos))) {
continue;
}
auto prev_operand = first_range->GetAssignedOperand(operand_cache());
auto cur_operand = second_range->GetAssignedOperand(operand_cache());
if (prev_operand->Equals(cur_operand)) continue;
int index = pos.InstructionIndex();
bool delay_insertion = false;
GapInstruction::InnerPosition gap_pos;
int gap_index = index;
if (code()->IsGapAt(index)) {
gap_pos = pos.IsInstructionStart() ? GapInstruction::START
: GapInstruction::END;
} else {
gap_index = pos.IsInstructionStart() ? (index - 1) : (index + 1);
delay_insertion = gap_index < index;
gap_pos = delay_insertion ? GapInstruction::END : GapInstruction::START;
}
auto move = code()->GapAt(gap_index)->GetOrCreateParallelMove(
gap_pos, code_zone());
if (!delay_insertion) {
move->AddMove(prev_operand, cur_operand, code_zone());
} else {
delayed_insertion_map.insert(
std::make_pair(std::make_pair(move, prev_operand), cur_operand));
}
}
}
if (delayed_insertion_map.empty()) return;
// Insert all the moves which should occur after the stored move.
ZoneVector<MoveOperands> to_insert(local_zone());
ZoneVector<MoveOperands*> to_eliminate(local_zone());
to_insert.reserve(4);
to_eliminate.reserve(4);
auto move = delayed_insertion_map.begin()->first.first;
for (auto it = delayed_insertion_map.begin();; ++it) {
bool done = it == delayed_insertion_map.end();
if (done || it->first.first != move) {
// Commit the MoveOperands for current ParallelMove.
for (auto move_ops : to_eliminate) {
move_ops->Eliminate();
}
for (auto move_ops : to_insert) {
move->AddMove(move_ops.source(), move_ops.destination(), code_zone());
}
first_range = second_range;
second_range = second_range->next();
if (done) break;
// Reset state.
to_eliminate.clear();
to_insert.clear();
move = it->first.first;
}
// Gather all MoveOperands for a single ParallelMove.
MoveOperands move_ops(it->first.second, it->second);
auto eliminate = move->PrepareInsertAfter(&move_ops);
to_insert.push_back(move_ops);
if (eliminate != nullptr) to_eliminate.push_back(eliminate);
}
}
......
......@@ -564,10 +564,6 @@ class RegisterAllocator FINAL : public ZoneObject {
void SetLiveRangeAssignedRegister(LiveRange* range, int reg);
// Return parallel move that should be used to connect ranges split at the
// given position.
ParallelMove* GetConnectingParallelMove(LifetimePosition pos);
// Return the block which contains give lifetime position.
const InstructionBlock* GetInstructionBlock(LifetimePosition pos);
......
......@@ -40,7 +40,6 @@ InstructionSequenceTest::InstructionSequenceTest()
num_general_registers_(kDefaultNRegs),
num_double_registers_(kDefaultNRegs),
instruction_blocks_(zone()),
current_instruction_index_(-1),
current_block_(nullptr),
block_returns_(false) {
InitializeRegisterNames();
......@@ -100,8 +99,8 @@ void InstructionSequenceTest::StartBlock() {
}
int InstructionSequenceTest::EndBlock(BlockCompletion completion) {
int instruction_index = kMinInt;
Instruction* InstructionSequenceTest::EndBlock(BlockCompletion completion) {
Instruction* result = nullptr;
if (block_returns_) {
CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough);
completion.type_ = kBlockEnd;
......@@ -110,22 +109,22 @@ int InstructionSequenceTest::EndBlock(BlockCompletion completion) {
case kBlockEnd:
break;
case kFallThrough:
instruction_index = EmitFallThrough();
result = EmitFallThrough();
break;
case kJump:
CHECK(!block_returns_);
instruction_index = EmitJump();
result = EmitJump();
break;
case kBranch:
CHECK(!block_returns_);
instruction_index = EmitBranch(completion.op_);
result = EmitBranch(completion.op_);
break;
}
completions_.push_back(completion);
CHECK(current_block_ != nullptr);
sequence()->EndBlock(current_block_->rpo_number());
current_block_ = nullptr;
return instruction_index;
return result;
}
......@@ -139,15 +138,15 @@ InstructionSequenceTest::VReg InstructionSequenceTest::Define(
TestOperand output_op) {
VReg vreg = NewReg();
InstructionOperand outputs[1]{ConvertOutputOp(vreg, output_op)};
Emit(vreg.value_, kArchNop, 1, outputs);
Emit(kArchNop, 1, outputs);
return vreg;
}
int InstructionSequenceTest::Return(TestOperand input_op_0) {
Instruction* InstructionSequenceTest::Return(TestOperand input_op_0) {
block_returns_ = true;
InstructionOperand inputs[1]{ConvertInputOp(input_op_0)};
return Emit(NewIndex(), kArchRet, 0, nullptr, 1, inputs);
return Emit(kArchRet, 0, nullptr, 1, inputs);
}
......@@ -192,12 +191,12 @@ InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant(
VReg vreg = NewReg();
sequence()->AddConstant(vreg.value_, Constant(imm));
InstructionOperand outputs[1]{ConstantOperand(vreg.value_)};
Emit(vreg.value_, kArchNop, 1, outputs);
Emit(kArchNop, 1, outputs);
return vreg;
}
int InstructionSequenceTest::EmitNop() { return Emit(NewIndex(), kArchNop); }
Instruction* InstructionSequenceTest::EmitNop() { return Emit(kArchNop); }
static size_t CountInputs(size_t size,
......@@ -210,16 +209,17 @@ static size_t CountInputs(size_t size,
}
int InstructionSequenceTest::EmitI(size_t input_size, TestOperand* inputs) {
Instruction* InstructionSequenceTest::EmitI(size_t input_size,
TestOperand* inputs) {
InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
return Emit(NewIndex(), kArchNop, 0, nullptr, input_size, mapped_inputs);
return Emit(kArchNop, 0, nullptr, input_size, mapped_inputs);
}
int InstructionSequenceTest::EmitI(TestOperand input_op_0,
TestOperand input_op_1,
TestOperand input_op_2,
TestOperand input_op_3) {
Instruction* InstructionSequenceTest::EmitI(TestOperand input_op_0,
TestOperand input_op_1,
TestOperand input_op_2,
TestOperand input_op_3) {
TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
return EmitI(CountInputs(arraysize(inputs), inputs), inputs);
}
......@@ -230,7 +230,7 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
VReg output_vreg = NewReg();
InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)};
InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
Emit(output_vreg.value_, kArchNop, 1, outputs, input_size, mapped_inputs);
Emit(kArchNop, 1, outputs, input_size, mapped_inputs);
return output_vreg;
}
......@@ -243,14 +243,36 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
}
InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI(
TestOperand output_op_0, TestOperand output_op_1, size_t input_size,
TestOperand* inputs) {
VRegPair output_vregs = std::make_pair(NewReg(), NewReg());
InstructionOperand outputs[2]{
ConvertOutputOp(output_vregs.first, output_op_0),
ConvertOutputOp(output_vregs.second, output_op_1)};
InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
Emit(kArchNop, 2, outputs, input_size, mapped_inputs);
return output_vregs;
}
InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI(
TestOperand output_op_0, TestOperand output_op_1, TestOperand input_op_0,
TestOperand input_op_1, TestOperand input_op_2, TestOperand input_op_3) {
TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
return EmitOOI(output_op_0, output_op_1,
CountInputs(arraysize(inputs), inputs), inputs);
}
InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
TestOperand output_op, size_t input_size, TestOperand* inputs) {
VReg output_vreg = NewReg();
InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)};
CHECK(UnallocatedOperand::cast(outputs[0]).HasFixedPolicy());
InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
Emit(output_vreg.value_, kArchCallCodeObject, 1, outputs, input_size,
mapped_inputs, 0, nullptr, true);
Emit(kArchCallCodeObject, 1, outputs, input_size, mapped_inputs, 0, nullptr,
true);
return output_vreg;
}
......@@ -263,36 +285,28 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
}
const Instruction* InstructionSequenceTest::GetInstruction(
int instruction_index) {
auto it = instructions_.find(instruction_index);
CHECK(it != instructions_.end());
return it->second;
}
int InstructionSequenceTest::EmitBranch(TestOperand input_op) {
Instruction* InstructionSequenceTest::EmitBranch(TestOperand input_op) {
InstructionOperand inputs[4]{ConvertInputOp(input_op), ConvertInputOp(Imm()),
ConvertInputOp(Imm()), ConvertInputOp(Imm())};
InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) |
FlagsConditionField::encode(kEqual);
auto instruction =
NewInstruction(opcode, 0, nullptr, 4, inputs)->MarkAsControl();
return AddInstruction(NewIndex(), instruction);
return AddInstruction(instruction);
}
int InstructionSequenceTest::EmitFallThrough() {
Instruction* InstructionSequenceTest::EmitFallThrough() {
auto instruction = NewInstruction(kArchNop, 0, nullptr)->MarkAsControl();
return AddInstruction(NewIndex(), instruction);
return AddInstruction(instruction);
}
int InstructionSequenceTest::EmitJump() {
Instruction* InstructionSequenceTest::EmitJump() {
InstructionOperand inputs[1]{ConvertInputOp(Imm())};
auto instruction =
NewInstruction(kArchJmp, 0, nullptr, 1, inputs)->MarkAsControl();
return AddInstruction(NewIndex(), instruction);
return AddInstruction(instruction);
}
......@@ -458,23 +472,20 @@ void InstructionSequenceTest::WireBlock(size_t block_offset, int jump_offset) {
}
int InstructionSequenceTest::Emit(int instruction_index, InstructionCode code,
size_t outputs_size,
InstructionOperand* outputs,
size_t inputs_size,
InstructionOperand* inputs, size_t temps_size,
InstructionOperand* temps, bool is_call) {
Instruction* InstructionSequenceTest::Emit(
InstructionCode code, size_t outputs_size, InstructionOperand* outputs,
size_t inputs_size, InstructionOperand* inputs, size_t temps_size,
InstructionOperand* temps, bool is_call) {
auto instruction = NewInstruction(code, outputs_size, outputs, inputs_size,
inputs, temps_size, temps);
if (is_call) instruction->MarkAsCall();
return AddInstruction(instruction_index, instruction);
return AddInstruction(instruction);
}
int InstructionSequenceTest::AddInstruction(int instruction_index,
Instruction* instruction) {
Instruction* InstructionSequenceTest::AddInstruction(Instruction* instruction) {
sequence()->AddInstruction(instruction);
return instruction_index;
return instruction;
}
} // namespace compiler
......
......@@ -27,6 +27,8 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
int value_;
};
typedef std::pair<VReg, VReg> VRegPair;
enum TestOperandType {
kInvalid,
kSameAsFirst,
......@@ -125,14 +127,14 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
void StartLoop(int loop_blocks);
void EndLoop();
void StartBlock();
int EndBlock(BlockCompletion completion = FallThrough());
Instruction* EndBlock(BlockCompletion completion = FallThrough());
TestOperand Imm(int32_t imm = 0);
VReg Define(TestOperand output_op);
VReg Parameter(TestOperand output_op = Reg()) { return Define(output_op); }
int Return(TestOperand input_op_0);
int Return(VReg vreg) { return Return(Reg(vreg, 0)); }
Instruction* Return(TestOperand input_op_0);
Instruction* Return(VReg vreg) { return Return(Reg(vreg, 0)); }
PhiInstruction* Phi(VReg incoming_vreg_0 = VReg(),
VReg incoming_vreg_1 = VReg(),
......@@ -142,27 +144,30 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
void SetInput(PhiInstruction* phi, size_t input, VReg vreg);
VReg DefineConstant(int32_t imm = 0);
int EmitNop();
int EmitI(size_t input_size, TestOperand* inputs);
int EmitI(TestOperand input_op_0 = TestOperand(),
TestOperand input_op_1 = TestOperand(),
TestOperand input_op_2 = TestOperand(),
TestOperand input_op_3 = TestOperand());
Instruction* EmitNop();
Instruction* EmitI(size_t input_size, TestOperand* inputs);
Instruction* EmitI(TestOperand input_op_0 = TestOperand(),
TestOperand input_op_1 = TestOperand(),
TestOperand input_op_2 = TestOperand(),
TestOperand input_op_3 = TestOperand());
VReg EmitOI(TestOperand output_op, size_t input_size, TestOperand* inputs);
VReg EmitOI(TestOperand output_op, TestOperand input_op_0 = TestOperand(),
TestOperand input_op_1 = TestOperand(),
TestOperand input_op_2 = TestOperand(),
TestOperand input_op_3 = TestOperand());
VRegPair EmitOOI(TestOperand output_op_0, TestOperand output_op_1,
size_t input_size, TestOperand* inputs);
VRegPair EmitOOI(TestOperand output_op_0, TestOperand output_op_1,
TestOperand input_op_0 = TestOperand(),
TestOperand input_op_1 = TestOperand(),
TestOperand input_op_2 = TestOperand(),
TestOperand input_op_3 = TestOperand());
VReg EmitCall(TestOperand output_op, size_t input_size, TestOperand* inputs);
VReg EmitCall(TestOperand output_op, TestOperand input_op_0 = TestOperand(),
TestOperand input_op_1 = TestOperand(),
TestOperand input_op_2 = TestOperand(),
TestOperand input_op_3 = TestOperand());
// Get defining instruction vreg or value returned at instruction creation
// time when there is no return value.
const Instruction* GetInstruction(int instruction_index);
InstructionBlock* current_block() const { return current_block_; }
int num_general_registers() const { return num_general_registers_; }
int num_double_registers() const { return num_double_registers_; }
......@@ -172,13 +177,12 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
private:
VReg NewReg() { return VReg(sequence()->NextVirtualRegister()); }
int NewIndex() { return current_instruction_index_--; }
static TestOperand Invalid() { return TestOperand(kInvalid, VReg()); }
int EmitBranch(TestOperand input_op);
int EmitFallThrough();
int EmitJump();
Instruction* EmitBranch(TestOperand input_op);
Instruction* EmitFallThrough();
Instruction* EmitJump();
Instruction* NewInstruction(InstructionCode code, size_t outputs_size,
InstructionOperand* outputs,
size_t inputs_size = 0,
......@@ -202,12 +206,13 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
InstructionBlock* NewBlock();
void WireBlock(size_t block_offset, int jump_offset);
int Emit(int instruction_index, InstructionCode code, size_t outputs_size = 0,
InstructionOperand* outputs = nullptr, size_t inputs_size = 0,
InstructionOperand* inputs = nullptr, size_t temps_size = 0,
InstructionOperand* temps = nullptr, bool is_call = false);
Instruction* Emit(InstructionCode code, size_t outputs_size = 0,
InstructionOperand* outputs = nullptr,
size_t inputs_size = 0,
InstructionOperand* inputs = nullptr, size_t temps_size = 0,
InstructionOperand* temps = nullptr, bool is_call = false);
int AddInstruction(int instruction_index, Instruction* instruction);
Instruction* AddInstruction(Instruction* instruction);
struct LoopData {
Rpo loop_header_;
......@@ -226,7 +231,6 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
// Block building state.
InstructionBlocks instruction_blocks_;
Instructions instructions_;
int current_instruction_index_;
Completions completions_;
LoopBlocks loop_blocks_;
InstructionBlock* current_block_;
......
......@@ -301,6 +301,31 @@ TEST_F(RegisterAllocatorTest, SplitBeforeInstruction) {
}
TEST_F(RegisterAllocatorTest, SplitBeforeInstruction2) {
const int kNumRegs = 6;
SetNumRegs(kNumRegs, kNumRegs);
StartBlock();
// Stack parameters/spilled values.
auto p_0 = Define(Slot(-1));
auto p_1 = Define(Slot(-2));
// Fill registers.
VReg values[kNumRegs];
for (size_t i = 0; i < arraysize(values); ++i) {
values[i] = Define(Reg(static_cast<int>(i)));
}
// values[0] and [1] will be split in the second half of this instruction.
EmitOOI(Reg(0), Reg(1), Reg(p_0, 0), Reg(p_1, 1));
EmitI(Reg(values[0]), Reg(values[1]));
EndBlock(Last());
Allocate();
}
TEST_F(RegisterAllocatorTest, NestedDiamondPhiMerge) {
// Outer diamond.
StartBlock();
......
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