| Index: src/compiler/register-allocator.cc
|
| diff --git a/src/compiler/register-allocator.cc b/src/compiler/register-allocator.cc
|
| index 403c344aee09209934a6581f0d5695aee71aeffd..75fc1c5f3266fbb1b38806791491ab4fa219a19e 100644
|
| --- a/src/compiler/register-allocator.cc
|
| +++ b/src/compiler/register-allocator.cc
|
| @@ -1705,6 +1705,7 @@ void ConstraintBuilder::MeetConstraintsAfter(int instr_index) {
|
| // Handle constant/fixed output operands.
|
| for (size_t i = 0; i < first->OutputCount(); i++) {
|
| InstructionOperand* output = first->OutputAt(i);
|
| + if (output->IsAllocated()) continue;
|
| if (output->IsConstant()) {
|
| int output_vreg = ConstantOperand::cast(output)->virtual_register();
|
| TopLevelLiveRange* range = data()->GetOrCreateLiveRangeFor(output_vreg);
|
| @@ -1751,8 +1752,10 @@ void ConstraintBuilder::MeetConstraintsAfter(int instr_index) {
|
|
|
| void ConstraintBuilder::MeetConstraintsBefore(int instr_index) {
|
| Instruction* second = code()->InstructionAt(instr_index);
|
| + ZoneMap<int, InstructionOperand> constraints(allocation_zone());
|
| +
|
| // Handle fixed input operands of second instruction.
|
| - for (size_t i = 0; i < second->InputCount(); i++) {
|
| + for (size_t i = 0; i < second->InputCount(); ++i) {
|
| InstructionOperand* input = second->InputAt(i);
|
| if (input->IsImmediate() || input->IsExplicit()) {
|
| continue; // Ignore immediates and explicitly reserved registers.
|
| @@ -1763,11 +1766,19 @@ void ConstraintBuilder::MeetConstraintsBefore(int instr_index) {
|
| UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg);
|
| bool is_tagged = code()->IsReference(input_vreg);
|
| AllocateFixed(cur_input, instr_index, is_tagged);
|
| + // TODO(mtrofin): refactor AllocateFixed, its behavior is
|
| + // not the most maintainable: cur_input is mutated.
|
| + if (cur_input->IsAnyRegister()) {
|
| + // It may be that the vreg is constrained to be in different registers.
|
| + // We just want one of them for the other potential non-fixed register
|
| + // uses.
|
| + constraints.insert(std::make_pair(input_vreg, *cur_input));
|
| + }
|
| data()->AddGapMove(instr_index, Instruction::END, input_copy, *cur_input);
|
| }
|
| }
|
| // Handle "output same as input" for second instruction.
|
| - for (size_t i = 0; i < second->OutputCount(); i++) {
|
| + for (size_t i = 0; i < second->OutputCount(); ++i) {
|
| InstructionOperand* output = second->OutputAt(i);
|
| if (!output->IsUnallocated()) continue;
|
| UnallocatedOperand* second_output = UnallocatedOperand::cast(output);
|
| @@ -1777,24 +1788,53 @@ void ConstraintBuilder::MeetConstraintsBefore(int instr_index) {
|
| UnallocatedOperand::cast(second->InputAt(0));
|
| int output_vreg = second_output->virtual_register();
|
| int input_vreg = cur_input->virtual_register();
|
| - UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg);
|
| - cur_input->set_virtual_register(second_output->virtual_register());
|
| - MoveOperands* gap_move = data()->AddGapMove(instr_index, Instruction::END,
|
| - input_copy, *cur_input);
|
| - if (code()->IsReference(input_vreg) && !code()->IsReference(output_vreg)) {
|
| - if (second->HasReferenceMap()) {
|
| - RegisterAllocationData::DelayedReference delayed_reference = {
|
| - second->reference_map(), &gap_move->source()};
|
| - data()->delayed_references().push_back(delayed_reference);
|
| - }
|
| - } else if (!code()->IsReference(input_vreg) &&
|
| - code()->IsReference(output_vreg)) {
|
| - // The input is assumed to immediately have a tagged representation,
|
| - // before the pointer map can be used. I.e. the pointer map at the
|
| - // instruction will include the output operand (whose value at the
|
| - // beginning of the instruction is equal to the input operand). If
|
| - // this is not desired, then the pointer map at this instruction needs
|
| - // to be adjusted manually.
|
| + if (constraints.count(input_vreg) > 0) {
|
| + InstructionOperand reg_operand = constraints[input_vreg];
|
| + InstructionOperand::ReplaceWith(second_output, ®_operand);
|
| + if (data()->code()->instructions().size() >
|
| + static_cast<size_t>(instr_index) + 1) {
|
| + UnallocatedOperand new_output_op(UnallocatedOperand::ANY, output_vreg);
|
| + data()->AddGapMove(instr_index + 1, Instruction::START, reg_operand,
|
| + new_output_op);
|
| + TopLevelLiveRange* range = data()->GetOrCreateLiveRangeFor(output_vreg);
|
| + range->RecordSpillLocation(allocation_zone(), instr_index + 1,
|
| + second_output);
|
| + range->SetSpillStartIndex(instr_index + 1);
|
| + }
|
| + } else {
|
| + UnallocatedOperand input_copy(UnallocatedOperand::ANY, input_vreg);
|
| + cur_input->set_virtual_register(second_output->virtual_register());
|
| + MoveOperands* gap_move = data()->AddGapMove(instr_index, Instruction::END,
|
| + input_copy, *cur_input);
|
| + if (code()->IsReference(input_vreg) &&
|
| + !code()->IsReference(output_vreg)) {
|
| + if (second->HasReferenceMap()) {
|
| + RegisterAllocationData::DelayedReference delayed_reference = {
|
| + second->reference_map(), &gap_move->source()};
|
| + data()->delayed_references().push_back(delayed_reference);
|
| + }
|
| + } else if (!code()->IsReference(input_vreg) &&
|
| + code()->IsReference(output_vreg)) {
|
| + // The input is assumed to immediately have a tagged representation,
|
| + // before the pointer map can be used. I.e. the pointer map at the
|
| + // instruction will include the output operand (whose value at the
|
| + // beginning of the instruction is equal to the input operand). If
|
| + // this is not desired, then the pointer map at this instruction needs
|
| + // to be adjusted manually.
|
| + }
|
| + }
|
| + }
|
| +
|
| + for (size_t i = 0; i < second->InputCount(); ++i) {
|
| + InstructionOperand* input = second->InputAt(i);
|
| + if (!input->IsUnallocated()) continue;
|
| + UnallocatedOperand* cur_input = UnallocatedOperand::cast(input);
|
| + if (cur_input->HasFixedPolicy() || cur_input->HasSlotPolicy()) {
|
| + continue;
|
| + }
|
| + int vreg = cur_input->virtual_register();
|
| + if (constraints.count(vreg) > 0) {
|
| + InstructionOperand::ReplaceWith(input, &constraints.at(vreg));
|
| }
|
| }
|
| }
|
|
|