Commit f5305393 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[Turboprop] Ensure constant operands are only used when allowed.

Previously it was possible for a slot operand to be allocated a
constant operand which is not valid. This CL adds support to the
mid-tier register allocator to keep track of whether spilled operands
can support constant operands, and if not to instead move the constant
to a spill slot at it's definition point, and use that spill slot
instead.

In the process of doing this, we can cleanup the hack that
required constants to always be allocated to a register for
REGISTER_OR_SLOT operator policies.

BUG=chromium:10772,v8:10772,v8:9684

Change-Id: I975ea2c481b45fc0855e175bc6dc2bd0a83f509a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2692569Reviewed-by: 's avatarSantiago Aboy Solanes <solanes@chromium.org>
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72722}
parent c5fd776d
...@@ -295,17 +295,18 @@ class VirtualRegisterData final { ...@@ -295,17 +295,18 @@ class VirtualRegisterData final {
// Spill an operand that is assigned to this virtual register. // Spill an operand that is assigned to this virtual register.
void SpillOperand(InstructionOperand* operand, int instr_index, void SpillOperand(InstructionOperand* operand, int instr_index,
bool has_constant_policy,
MidTierRegisterAllocationData* data); MidTierRegisterAllocationData* data);
// Emit gap moves to / from the spill slot. // Emit gap moves to / from the spill slot.
void EmitGapMoveToInputFromSpillSlot(AllocatedOperand to_operand, void EmitGapMoveToInputFromSpillSlot(InstructionOperand to_operand,
int instr_index, int instr_index,
MidTierRegisterAllocationData* data); MidTierRegisterAllocationData* data);
void EmitGapMoveFromOutputToSpillSlot(AllocatedOperand from_operand, void EmitGapMoveFromOutputToSpillSlot(InstructionOperand from_operand,
const InstructionBlock* current_block, const InstructionBlock* current_block,
int instr_index, int instr_index,
MidTierRegisterAllocationData* data); MidTierRegisterAllocationData* data);
void EmitGapMoveToSpillSlot(AllocatedOperand from_operand, int instr_index, void EmitGapMoveToSpillSlot(InstructionOperand from_operand, int instr_index,
MidTierRegisterAllocationData* data); MidTierRegisterAllocationData* data);
// Adds pending spills for deferred-blocks. // Adds pending spills for deferred-blocks.
...@@ -328,14 +329,14 @@ class VirtualRegisterData final { ...@@ -328,14 +329,14 @@ class VirtualRegisterData final {
return HasSpillOperand() && spill_operand_->IsAllocated(); return HasSpillOperand() && spill_operand_->IsAllocated();
} }
bool HasConstantSpillOperand() const { bool HasConstantSpillOperand() const {
DCHECK_EQ(is_constant(), HasSpillOperand() && spill_operand_->IsConstant()); return HasSpillOperand() && spill_operand_->IsConstant();
return is_constant();
} }
// Returns true if the virtual register should be spilled when it is output. // Returns true if the virtual register should be spilled when it is output.
bool NeedsSpillAtOutput() const { return needs_spill_at_output_; } bool NeedsSpillAtOutput() const { return needs_spill_at_output_; }
void MarkAsNeedsSpillAtOutput() { void MarkAsNeedsSpillAtOutput() {
if (is_constant()) return; if (HasConstantSpillOperand()) return;
needs_spill_at_output_ = true; needs_spill_at_output_ = true;
if (HasSpillRange()) spill_range()->ClearDeferredBlockSpills(); if (HasSpillRange()) spill_range()->ClearDeferredBlockSpills();
} }
...@@ -548,7 +549,8 @@ void VirtualRegisterData::DefineAsPhi(int virtual_register, int instr_index, ...@@ -548,7 +549,8 @@ void VirtualRegisterData::DefineAsPhi(int virtual_register, int instr_index,
void VirtualRegisterData::EnsureSpillRange( void VirtualRegisterData::EnsureSpillRange(
MidTierRegisterAllocationData* data) { MidTierRegisterAllocationData* data) {
DCHECK(!is_constant()); DCHECK(!HasConstantSpillOperand());
if (HasSpillRange()) return; if (HasSpillRange()) return;
const InstructionBlock* definition_block = const InstructionBlock* definition_block =
...@@ -578,7 +580,7 @@ void VirtualRegisterData::EnsureSpillRange( ...@@ -578,7 +580,7 @@ void VirtualRegisterData::EnsureSpillRange(
void VirtualRegisterData::AddSpillUse(int instr_index, void VirtualRegisterData::AddSpillUse(int instr_index,
MidTierRegisterAllocationData* data) { MidTierRegisterAllocationData* data) {
if (is_constant()) return; if (HasConstantSpillOperand()) return;
EnsureSpillRange(data); EnsureSpillRange(data);
spill_range_->ExtendRangeTo(instr_index); spill_range_->ExtendRangeTo(instr_index);
...@@ -615,7 +617,14 @@ void VirtualRegisterData::AddDeferredSpillOutput( ...@@ -615,7 +617,14 @@ void VirtualRegisterData::AddDeferredSpillOutput(
void VirtualRegisterData::SpillOperand(InstructionOperand* operand, void VirtualRegisterData::SpillOperand(InstructionOperand* operand,
int instr_index, int instr_index,
bool has_constant_policy,
MidTierRegisterAllocationData* data) { MidTierRegisterAllocationData* data) {
if (!has_constant_policy && HasConstantSpillOperand()) {
// Reset the constant spill operand to force a real spill slot since this
// operand can't use the constant spill operand.
spill_operand_ = nullptr;
DCHECK(!HasConstantSpillOperand());
}
AddSpillUse(instr_index, data); AddSpillUse(instr_index, data);
if (HasAllocatedSpillOperand() || HasConstantSpillOperand()) { if (HasAllocatedSpillOperand() || HasConstantSpillOperand()) {
InstructionOperand::ReplaceWith(operand, spill_operand()); InstructionOperand::ReplaceWith(operand, spill_operand());
...@@ -640,7 +649,7 @@ void VirtualRegisterData::EmitDeferredSpillOutputs( ...@@ -640,7 +649,7 @@ void VirtualRegisterData::EmitDeferredSpillOutputs(
} }
void VirtualRegisterData::EmitGapMoveToInputFromSpillSlot( void VirtualRegisterData::EmitGapMoveToInputFromSpillSlot(
AllocatedOperand to_operand, int instr_index, InstructionOperand to_operand, int instr_index,
MidTierRegisterAllocationData* data) { MidTierRegisterAllocationData* data) {
AddSpillUse(instr_index, data); AddSpillUse(instr_index, data);
DCHECK(!to_operand.IsPending()); DCHECK(!to_operand.IsPending());
...@@ -656,7 +665,7 @@ void VirtualRegisterData::EmitGapMoveToInputFromSpillSlot( ...@@ -656,7 +665,7 @@ void VirtualRegisterData::EmitGapMoveToInputFromSpillSlot(
} }
void VirtualRegisterData::EmitGapMoveToSpillSlot( void VirtualRegisterData::EmitGapMoveToSpillSlot(
AllocatedOperand from_operand, int instr_index, InstructionOperand from_operand, int instr_index,
MidTierRegisterAllocationData* data) { MidTierRegisterAllocationData* data) {
AddSpillUse(instr_index, data); AddSpillUse(instr_index, data);
if (HasAllocatedSpillOperand() || HasConstantSpillOperand()) { if (HasAllocatedSpillOperand() || HasConstantSpillOperand()) {
...@@ -671,7 +680,7 @@ void VirtualRegisterData::EmitGapMoveToSpillSlot( ...@@ -671,7 +680,7 @@ void VirtualRegisterData::EmitGapMoveToSpillSlot(
} }
void VirtualRegisterData::EmitGapMoveFromOutputToSpillSlot( void VirtualRegisterData::EmitGapMoveFromOutputToSpillSlot(
AllocatedOperand from_operand, const InstructionBlock* current_block, InstructionOperand from_operand, const InstructionBlock* current_block,
int instr_index, MidTierRegisterAllocationData* data) { int instr_index, MidTierRegisterAllocationData* data) {
DCHECK_EQ(data->GetBlock(instr_index), current_block); DCHECK_EQ(data->GetBlock(instr_index), current_block);
if (instr_index == current_block->last_instruction_index()) { if (instr_index == current_block->last_instruction_index()) {
...@@ -760,7 +769,8 @@ class RegisterState final : public ZoneObject { ...@@ -760,7 +769,8 @@ class RegisterState final : public ZoneObject {
// this register, then |operand| will be too, otherwise |operand| will be // this register, then |operand| will be too, otherwise |operand| will be
// replaced with |virtual_register|'s spill operand. // replaced with |virtual_register|'s spill operand.
void AllocatePendingUse(RegisterIndex reg, int virtual_register, void AllocatePendingUse(RegisterIndex reg, int virtual_register,
InstructionOperand* operand, int instr_index); InstructionOperand* operand, bool can_be_constant,
int instr_index);
// Mark that the register is holding a phi operand that is yet to be allocated // Mark that the register is holding a phi operand that is yet to be allocated
// by the source block in the gap just before the last instruction in the // by the source block in the gap just before the last instruction in the
...@@ -816,7 +826,7 @@ class RegisterState final : public ZoneObject { ...@@ -816,7 +826,7 @@ class RegisterState final : public ZoneObject {
MidTierRegisterAllocationData* data); MidTierRegisterAllocationData* data);
void Use(int virtual_register, int instr_index); void Use(int virtual_register, int instr_index);
void PendingUse(InstructionOperand* operand, int virtual_register, void PendingUse(InstructionOperand* operand, int virtual_register,
int instr_index); bool can_be_constant, int instr_index);
void SpillForDeferred(AllocatedOperand allocated, int instr_index, void SpillForDeferred(AllocatedOperand allocated, int instr_index,
MidTierRegisterAllocationData* data); MidTierRegisterAllocationData* data);
void MoveToSpillSlotOnDeferred(int virtual_register, int instr_index, void MoveToSpillSlotOnDeferred(int virtual_register, int instr_index,
...@@ -881,6 +891,7 @@ class RegisterState final : public ZoneObject { ...@@ -881,6 +891,7 @@ class RegisterState final : public ZoneObject {
bool needs_gap_move_on_spill_; bool needs_gap_move_on_spill_;
bool is_shared_; bool is_shared_;
bool is_phi_gap_move_; bool is_phi_gap_move_;
bool pending_uses_can_use_constant_;
int last_use_instr_index_; int last_use_instr_index_;
int num_commits_required_; int num_commits_required_;
...@@ -910,6 +921,7 @@ void RegisterState::Register::Reset() { ...@@ -910,6 +921,7 @@ void RegisterState::Register::Reset() {
is_shared_ = false; is_shared_ = false;
is_phi_gap_move_ = false; is_phi_gap_move_ = false;
needs_gap_move_on_spill_ = false; needs_gap_move_on_spill_ = false;
pending_uses_can_use_constant_ = true;
last_use_instr_index_ = -1; last_use_instr_index_ = -1;
num_commits_required_ = 0; num_commits_required_ = 0;
virtual_register_ = InstructionOperand::kInvalidVirtualRegister; virtual_register_ = InstructionOperand::kInvalidVirtualRegister;
...@@ -930,6 +942,7 @@ void RegisterState::Register::Use(int virtual_register, int instr_index) { ...@@ -930,6 +942,7 @@ void RegisterState::Register::Use(int virtual_register, int instr_index) {
void RegisterState::Register::PendingUse(InstructionOperand* operand, void RegisterState::Register::PendingUse(InstructionOperand* operand,
int virtual_register, int virtual_register,
bool can_be_constant,
int instr_index) { int instr_index) {
if (!is_allocated()) { if (!is_allocated()) {
virtual_register_ = virtual_register; virtual_register_ = virtual_register;
...@@ -937,6 +950,7 @@ void RegisterState::Register::PendingUse(InstructionOperand* operand, ...@@ -937,6 +950,7 @@ void RegisterState::Register::PendingUse(InstructionOperand* operand,
num_commits_required_ = 1; num_commits_required_ = 1;
} }
DCHECK_EQ(virtual_register_, virtual_register); DCHECK_EQ(virtual_register_, virtual_register);
pending_uses_can_use_constant_ &= can_be_constant;
PendingOperand pending_op(pending_uses()); PendingOperand pending_op(pending_uses());
InstructionOperand::ReplaceWith(operand, &pending_op); InstructionOperand::ReplaceWith(operand, &pending_op);
...@@ -1063,7 +1077,8 @@ void RegisterState::Register::SpillPendingUses( ...@@ -1063,7 +1077,8 @@ void RegisterState::Register::SpillPendingUses(
while (pending_use) { while (pending_use) {
// Spill all the pending operands associated with this register. // Spill all the pending operands associated with this register.
PendingOperand* next = pending_use->next(); PendingOperand* next = pending_use->next();
vreg_data.SpillOperand(pending_use, last_use_instr_index(), data); vreg_data.SpillOperand(pending_use, last_use_instr_index(),
pending_uses_can_use_constant_, data);
pending_use = next; pending_use = next;
} }
pending_uses_ = nullptr; pending_uses_ = nullptr;
...@@ -1158,9 +1173,10 @@ void RegisterState::AllocateUse(RegisterIndex reg, int virtual_register, ...@@ -1158,9 +1173,10 @@ void RegisterState::AllocateUse(RegisterIndex reg, int virtual_register,
void RegisterState::AllocatePendingUse(RegisterIndex reg, int virtual_register, void RegisterState::AllocatePendingUse(RegisterIndex reg, int virtual_register,
InstructionOperand* operand, InstructionOperand* operand,
int instr_index) { bool can_be_constant, int instr_index) {
EnsureRegisterData(reg); EnsureRegisterData(reg);
reg_data(reg).PendingUse(operand, virtual_register, instr_index); reg_data(reg).PendingUse(operand, virtual_register, can_be_constant,
instr_index);
} }
void RegisterState::UseForPhiGapMove(RegisterIndex reg) { void RegisterState::UseForPhiGapMove(RegisterIndex reg) {
...@@ -1297,7 +1313,7 @@ class SinglePassRegisterAllocator final { ...@@ -1297,7 +1313,7 @@ class SinglePassRegisterAllocator final {
// Allocation routines used to allocate a particular operand to either a // Allocation routines used to allocate a particular operand to either a
// register or a spill slot. // register or a spill slot.
void AllocateConstantOutput(ConstantOperand* operand); void AllocateConstantOutput(ConstantOperand* operand, int instr_index);
void AllocateOutput(UnallocatedOperand* operand, int instr_index); void AllocateOutput(UnallocatedOperand* operand, int instr_index);
void AllocateInput(UnallocatedOperand* operand, int instr_index); void AllocateInput(UnallocatedOperand* operand, int instr_index);
void AllocateSameInputOutput(UnallocatedOperand* output, void AllocateSameInputOutput(UnallocatedOperand* output,
...@@ -1387,7 +1403,8 @@ class SinglePassRegisterAllocator final { ...@@ -1387,7 +1403,8 @@ class SinglePassRegisterAllocator final {
// register is not subsequently spilled) for |operand| of the instruction at // register is not subsequently spilled) for |operand| of the instruction at
// |instr_index|. // |instr_index|.
void AllocatePendingUse(RegisterIndex reg, int virtual_register, void AllocatePendingUse(RegisterIndex reg, int virtual_register,
InstructionOperand* operand, int instr_index); InstructionOperand* operand, bool can_be_constant,
int instr_index);
// Allocate |operand| to |reg| and add a gap move to move |virtual_register| // Allocate |operand| to |reg| and add a gap move to move |virtual_register|
// to this register for the instruction at |instr_index|. |reg| will be // to this register for the instruction at |instr_index|. |reg| will be
...@@ -1771,7 +1788,8 @@ void SinglePassRegisterAllocator::MoveRegisterOnMerge( ...@@ -1771,7 +1788,8 @@ void SinglePassRegisterAllocator::MoveRegisterOnMerge(
data()->AddPendingOperandGapMove(instr_index, Instruction::START); data()->AddPendingOperandGapMove(instr_index, Instruction::START);
succ_state->Commit(to, AllocatedOperandForReg(to, virtual_register), succ_state->Commit(to, AllocatedOperandForReg(to, virtual_register),
&move->destination(), data()); &move->destination(), data());
AllocatePendingUse(from, virtual_register, &move->source(), instr_index); AllocatePendingUse(from, virtual_register, &move->source(), true,
instr_index);
} }
void SinglePassRegisterAllocator::UpdateVirtualRegisterState() { void SinglePassRegisterAllocator::UpdateVirtualRegisterState() {
...@@ -2145,12 +2163,12 @@ void SinglePassRegisterAllocator::AllocateUse(RegisterIndex reg, ...@@ -2145,12 +2163,12 @@ void SinglePassRegisterAllocator::AllocateUse(RegisterIndex reg,
void SinglePassRegisterAllocator::AllocatePendingUse( void SinglePassRegisterAllocator::AllocatePendingUse(
RegisterIndex reg, int virtual_register, InstructionOperand* operand, RegisterIndex reg, int virtual_register, InstructionOperand* operand,
int instr_index) { bool can_be_constant, int instr_index) {
DCHECK_NE(virtual_register, InstructionOperand::kInvalidVirtualRegister); DCHECK_NE(virtual_register, InstructionOperand::kInvalidVirtualRegister);
DCHECK(IsFreeOrSameVirtualRegister(reg, virtual_register)); DCHECK(IsFreeOrSameVirtualRegister(reg, virtual_register));
register_state()->AllocatePendingUse(reg, virtual_register, operand, register_state()->AllocatePendingUse(reg, virtual_register, operand,
instr_index); can_be_constant, instr_index);
// Since this is a pending use and the operand doesn't need to use a register, // Since this is a pending use and the operand doesn't need to use a register,
// allocate with UsePosition::kNone to avoid blocking it's use by other // allocate with UsePosition::kNone to avoid blocking it's use by other
// operands in this instruction. // operands in this instruction.
...@@ -2163,7 +2181,7 @@ void SinglePassRegisterAllocator::AllocateUseWithMove( ...@@ -2163,7 +2181,7 @@ void SinglePassRegisterAllocator::AllocateUseWithMove(
int instr_index, UsePosition pos) { int instr_index, UsePosition pos) {
AllocatedOperand to = AllocatedOperandForReg(reg, virtual_register); AllocatedOperand to = AllocatedOperandForReg(reg, virtual_register);
UnallocatedOperand from = UnallocatedOperand( UnallocatedOperand from = UnallocatedOperand(
UnallocatedOperand::REGISTER_OR_SLOT, virtual_register); UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT, virtual_register);
data()->AddGapMove(instr_index, Instruction::END, from, to); data()->AddGapMove(instr_index, Instruction::END, from, to);
InstructionOperand::ReplaceWith(operand, &to); InstructionOperand::ReplaceWith(operand, &to);
MarkRegisterUse(reg, RepresentationFor(virtual_register), pos); MarkRegisterUse(reg, RepresentationFor(virtual_register), pos);
...@@ -2187,17 +2205,17 @@ void SinglePassRegisterAllocator::AllocateInput(UnallocatedOperand* operand, ...@@ -2187,17 +2205,17 @@ void SinglePassRegisterAllocator::AllocateInput(UnallocatedOperand* operand,
// instruction since the allocation needs to reflect the state before // instruction since the allocation needs to reflect the state before
// the instruction (at the gap move). For now spilling is fine since // the instruction (at the gap move). For now spilling is fine since
// fixed slot inputs are uncommon. // fixed slot inputs are uncommon.
UnallocatedOperand input_copy(UnallocatedOperand::REGISTER_OR_SLOT, UnallocatedOperand input_copy(
virtual_register); UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT, virtual_register);
AllocatedOperand allocated = AllocatedOperand( AllocatedOperand allocated = AllocatedOperand(
AllocatedOperand::STACK_SLOT, rep, operand->fixed_slot_index()); AllocatedOperand::STACK_SLOT, rep, operand->fixed_slot_index());
InstructionOperand::ReplaceWith(operand, &allocated); InstructionOperand::ReplaceWith(operand, &allocated);
MoveOperands* move_op = MoveOperands* move_op =
data()->AddGapMove(instr_index, Instruction::END, input_copy, *operand); data()->AddGapMove(instr_index, Instruction::END, input_copy, *operand);
vreg_data.SpillOperand(&move_op->source(), instr_index, data()); vreg_data.SpillOperand(&move_op->source(), instr_index, true, data());
return; return;
} else if (operand->HasSlotPolicy()) { } else if (operand->HasSlotPolicy()) {
vreg_data.SpillOperand(operand, instr_index, data()); vreg_data.SpillOperand(operand, instr_index, false, data());
return; return;
} }
...@@ -2217,9 +2235,7 @@ void SinglePassRegisterAllocator::AllocateInput(UnallocatedOperand* operand, ...@@ -2217,9 +2235,7 @@ void SinglePassRegisterAllocator::AllocateInput(UnallocatedOperand* operand,
AllocateUse(reg, virtual_register, operand, instr_index, pos); AllocateUse(reg, virtual_register, operand, instr_index, pos);
} }
} else { } else {
bool must_use_register = operand->HasRegisterPolicy() || bool must_use_register = operand->HasRegisterPolicy();
(vreg_data.is_constant() &&
!operand->HasRegisterOrSlotOrConstantPolicy());
RegisterIndex reg = RegisterIndex reg =
ChooseRegisterFor(vreg_data, instr_index, pos, must_use_register); ChooseRegisterFor(vreg_data, instr_index, pos, must_use_register);
...@@ -2227,10 +2243,14 @@ void SinglePassRegisterAllocator::AllocateInput(UnallocatedOperand* operand, ...@@ -2227,10 +2243,14 @@ void SinglePassRegisterAllocator::AllocateInput(UnallocatedOperand* operand,
if (must_use_register) { if (must_use_register) {
AllocateUse(reg, virtual_register, operand, instr_index, pos); AllocateUse(reg, virtual_register, operand, instr_index, pos);
} else { } else {
AllocatePendingUse(reg, virtual_register, operand, instr_index); AllocatePendingUse(reg, virtual_register, operand,
operand->HasRegisterOrSlotOrConstantPolicy(),
instr_index);
} }
} else { } else {
vreg_data.SpillOperand(operand, instr_index, data()); vreg_data.SpillOperand(operand, instr_index,
operand->HasRegisterOrSlotOrConstantPolicy(),
data());
} }
} }
} }
...@@ -2242,23 +2262,28 @@ void SinglePassRegisterAllocator::AllocateGapMoveInput( ...@@ -2242,23 +2262,28 @@ void SinglePassRegisterAllocator::AllocateGapMoveInput(
VirtualRegisterData& vreg_data = VirtualRegisterDataFor(virtual_register); VirtualRegisterData& vreg_data = VirtualRegisterDataFor(virtual_register);
// Gap move inputs should be unconstrained. // Gap move inputs should be unconstrained.
DCHECK(operand->HasRegisterOrSlotPolicy()); DCHECK(operand->HasRegisterOrSlotOrConstantPolicy());
RegisterIndex reg = RegisterIndex reg =
ChooseRegisterFor(vreg_data, instr_index, UsePosition::kStart, false); ChooseRegisterFor(vreg_data, instr_index, UsePosition::kStart, false);
if (reg.is_valid()) { if (reg.is_valid()) {
AllocatePendingUse(reg, virtual_register, operand, instr_index); AllocatePendingUse(reg, virtual_register, operand, true, instr_index);
} else { } else {
vreg_data.SpillOperand(operand, instr_index, data()); vreg_data.SpillOperand(operand, instr_index, true, data());
} }
} }
void SinglePassRegisterAllocator::AllocateConstantOutput( void SinglePassRegisterAllocator::AllocateConstantOutput(
ConstantOperand* operand) { ConstantOperand* operand, int instr_index) {
EnsureRegisterState(); EnsureRegisterState();
// If the constant is allocated to a register, spill it now to add the // If the constant is allocated to a register, spill it now to add the
// necessary gap moves from the constant operand to the register. // necessary gap moves from the constant operand to the register.
int virtual_register = operand->virtual_register(); int virtual_register = operand->virtual_register();
VirtualRegisterData& vreg_data = VirtualRegisterDataFor(virtual_register);
SpillRegisterForVirtualRegister(virtual_register); SpillRegisterForVirtualRegister(virtual_register);
if (vreg_data.NeedsSpillAtOutput()) {
vreg_data.EmitGapMoveFromOutputToSpillSlot(*operand, current_block(),
instr_index, data());
}
} }
void SinglePassRegisterAllocator::AllocateOutput(UnallocatedOperand* operand, void SinglePassRegisterAllocator::AllocateOutput(UnallocatedOperand* operand,
...@@ -2288,7 +2313,7 @@ RegisterIndex SinglePassRegisterAllocator::AllocateOutput( ...@@ -2288,7 +2313,7 @@ RegisterIndex SinglePassRegisterAllocator::AllocateOutput(
// TODO(rmcilroy): support secondary storage. // TODO(rmcilroy): support secondary storage.
if (!reg.is_valid()) { if (!reg.is_valid()) {
vreg_data.SpillOperand(operand, instr_index, data()); vreg_data.SpillOperand(operand, instr_index, false, data());
} else { } else {
InstructionOperand move_output_to; InstructionOperand move_output_to;
if (!VirtualRegisterIsUnallocatedOrInReg(virtual_register, reg)) { if (!VirtualRegisterIsUnallocatedOrInReg(virtual_register, reg)) {
...@@ -2349,14 +2374,14 @@ void SinglePassRegisterAllocator::AllocateSameInputOutput( ...@@ -2349,14 +2374,14 @@ void SinglePassRegisterAllocator::AllocateSameInputOutput(
// virtual register's spill slot, then add a gap-move to move the input // virtual register's spill slot, then add a gap-move to move the input
// value into this spill slot. // value into this spill slot.
VirtualRegisterData& output_vreg_data = VirtualRegisterDataFor(output_vreg); VirtualRegisterData& output_vreg_data = VirtualRegisterDataFor(output_vreg);
output_vreg_data.SpillOperand(input, instr_index, data()); output_vreg_data.SpillOperand(input, instr_index, false, data());
// Add an unconstrained gap move for the input virtual register. // Add an unconstrained gap move for the input virtual register.
UnallocatedOperand unconstrained_input(UnallocatedOperand::REGISTER_OR_SLOT, UnallocatedOperand unconstrained_input(
input_vreg); UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT, input_vreg);
MoveOperands* move_ops = data()->AddGapMove( MoveOperands* move_ops = data()->AddGapMove(
instr_index, Instruction::END, unconstrained_input, PendingOperand()); instr_index, Instruction::END, unconstrained_input, PendingOperand());
output_vreg_data.SpillOperand(&move_ops->destination(), instr_index, output_vreg_data.SpillOperand(&move_ops->destination(), instr_index, true,
data()); data());
} }
} }
...@@ -2384,7 +2409,9 @@ void SinglePassRegisterAllocator::AllocateTemp(UnallocatedOperand* operand, ...@@ -2384,7 +2409,9 @@ void SinglePassRegisterAllocator::AllocateTemp(UnallocatedOperand* operand,
CommitRegister(reg, virtual_register, operand, UsePosition::kAll); CommitRegister(reg, virtual_register, operand, UsePosition::kAll);
} else { } else {
VirtualRegisterData& vreg_data = VirtualRegisterDataFor(virtual_register); VirtualRegisterData& vreg_data = VirtualRegisterDataFor(virtual_register);
vreg_data.SpillOperand(operand, instr_index, data()); vreg_data.SpillOperand(operand, instr_index,
operand->HasRegisterOrSlotOrConstantPolicy(),
data());
} }
} }
...@@ -2463,12 +2490,12 @@ void SinglePassRegisterAllocator::AllocatePhiGapMove(int to_vreg, int from_vreg, ...@@ -2463,12 +2490,12 @@ void SinglePassRegisterAllocator::AllocatePhiGapMove(int to_vreg, int from_vreg,
CommitRegister(to_register, to_vreg, to_operand, UsePosition::kAll); CommitRegister(to_register, to_vreg, to_operand, UsePosition::kAll);
} else { } else {
VirtualRegisterDataFor(to_vreg).SpillOperand(to_operand, instr_index, VirtualRegisterDataFor(to_vreg).SpillOperand(to_operand, instr_index,
data()); true, data());
} }
// The from side is unconstrained. // The from side is unconstrained.
UnallocatedOperand unconstrained_input(UnallocatedOperand::REGISTER_OR_SLOT, UnallocatedOperand unconstrained_input(
from_vreg); UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT, from_vreg);
InstructionOperand::ReplaceWith(from_operand, &unconstrained_input); InstructionOperand::ReplaceWith(from_operand, &unconstrained_input);
} }
} }
...@@ -2775,7 +2802,8 @@ void MidTierRegisterAllocator::AllocateRegisters( ...@@ -2775,7 +2802,8 @@ void MidTierRegisterAllocator::AllocateRegisters(
DCHECK(!output->IsAllocated()); DCHECK(!output->IsAllocated());
if (output->IsConstant()) { if (output->IsConstant()) {
ConstantOperand* constant_operand = ConstantOperand::cast(output); ConstantOperand* constant_operand = ConstantOperand::cast(output);
AllocatorFor(constant_operand).AllocateConstantOutput(constant_operand); AllocatorFor(constant_operand)
.AllocateConstantOutput(constant_operand, instr_index);
} else { } else {
UnallocatedOperand* unallocated_output = UnallocatedOperand* unallocated_output =
UnallocatedOperand::cast(output); UnallocatedOperand::cast(output);
......
...@@ -2376,7 +2376,7 @@ struct ResolveControlFlowPhase { ...@@ -2376,7 +2376,7 @@ struct ResolveControlFlowPhase {
}; };
struct MidTierRegisterOutputDefinitionPhase { struct MidTierRegisterOutputDefinitionPhase {
DECL_PIPELINE_PHASE_CONSTANTS(MidTierRegisterAllocator) DECL_PIPELINE_PHASE_CONSTANTS(MidTierRegisterOutputDefinition)
void Run(PipelineData* data, Zone* temp_zone) { void Run(PipelineData* data, Zone* temp_zone) {
DefineOutputs(data->mid_tier_register_allocator_data()); DefineOutputs(data->mid_tier_register_allocator_data());
......
...@@ -643,6 +643,18 @@ TEST_F(MidTierRegisterAllocatorTest, RegressionSpillDeoptInputIfUsedAtEnd) { ...@@ -643,6 +643,18 @@ TEST_F(MidTierRegisterAllocatorTest, RegressionSpillDeoptInputIfUsedAtEnd) {
EXPECT_FALSE(instr->InputAt(0)->EqualsCanonicalized(*instr->InputAt(1))); EXPECT_FALSE(instr->InputAt(0)->EqualsCanonicalized(*instr->InputAt(1)));
} }
TEST_F(MidTierRegisterAllocatorTest, RegressionConstantInSlotOperands) {
StartBlock();
auto const_var1 = DefineConstant(1);
auto const_var2 = DefineConstant(2);
EmitOI(Reg(), Slot(const_var1));
VReg out = EmitOI(Same(), Slot(const_var2));
Return(out);
EndBlock(Last());
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, DiamondWithCallFirstBlock) { TEST_F(MidTierRegisterAllocatorTest, DiamondWithCallFirstBlock) {
StartBlock(); StartBlock();
auto x = EmitOI(Reg(0)); auto x = EmitOI(Reg(0));
......
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