[cpp20] Fixes undefined behaviour on mid tier regalloc

Fixes undefined behavior, which manifests as a compiler error in C++20 in Google3.

This was caused by using members of vector<T> before T has been defined.
This change just massages the code a bit to get everything in the proper order.

See cl/468678068 on Google3.

Bug: chromium:1284275
Change-Id: I0b65e7f850e8dd1ed482be1b5cc0b8d9d77776eb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3859343
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82745}
This commit is contained in:
Victor Gomes 2022-08-26 14:29:37 +02:00 committed by V8 LUCI CQ
parent 32b7b8e903
commit bcda1e7647

View File

@ -24,89 +24,6 @@ namespace compiler {
class RegisterState;
class DeferredBlocksRegion;
// BlockState stores details associated with a particular basic block.
class BlockState final {
public:
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(BlockState);
explicit BlockState(Zone* zone) : dominated_blocks_(zone) {}
// Returns the RegisterState that applies to the input of this block. Can be
// |nullptr| if the no registers of |kind| have been allocated up to this
// point.
RegisterState* register_in_state(RegisterKind kind);
void set_register_in_state(RegisterState* register_state, RegisterKind kind);
// Returns a bitvector representing all the basic blocks that are dominated
// by this basic block.
SparseBitVector* dominated_blocks() { return &dominated_blocks_; }
// Set / get this block's index for successor's phi operations. Will return
// -1 if this block has no successor's with phi operations.
int successors_phi_index() const { return successors_phi_index_; }
void set_successors_phi_index(int index) {
DCHECK_EQ(successors_phi_index_, -1);
successors_phi_index_ = index;
}
// If this block is deferred, this represents region of deferred blocks
// that are directly reachable from this block.
DeferredBlocksRegion* deferred_blocks_region() const {
return deferred_blocks_region_;
}
void set_deferred_blocks_region(DeferredBlocksRegion* region) {
DCHECK_NULL(deferred_blocks_region_);
deferred_blocks_region_ = region;
}
// Returns true if this block represents either a transition from
// non-deferred to deferred or vice versa.
bool is_deferred_block_boundary() const {
return is_deferred_block_boundary_;
}
void MarkAsDeferredBlockBoundary() { is_deferred_block_boundary_ = true; }
private:
RegisterState* general_registers_in_state_ = nullptr;
RegisterState* double_registers_in_state_ = nullptr;
RegisterState* simd128_registers_in_state_ = nullptr;
DeferredBlocksRegion* deferred_blocks_region_ = nullptr;
SparseBitVector dominated_blocks_;
int successors_phi_index_ = -1;
bool is_deferred_block_boundary_ = false;
};
RegisterState* BlockState::register_in_state(RegisterKind kind) {
switch (kind) {
case RegisterKind::kGeneral:
return general_registers_in_state_;
case RegisterKind::kDouble:
return double_registers_in_state_;
case RegisterKind::kSimd128:
return simd128_registers_in_state_;
}
}
void BlockState::set_register_in_state(RegisterState* register_state,
RegisterKind kind) {
switch (kind) {
case RegisterKind::kGeneral:
DCHECK_NULL(general_registers_in_state_);
general_registers_in_state_ = register_state;
break;
case RegisterKind::kDouble:
DCHECK_NULL(double_registers_in_state_);
double_registers_in_state_ = register_state;
break;
case RegisterKind::kSimd128:
DCHECK_NULL(simd128_registers_in_state_);
simd128_registers_in_state_ = register_state;
break;
}
}
// A Range from [start, end] of instructions, inclusive of start and end.
class Range {
public:
@ -134,41 +51,6 @@ class Range {
int end_;
};
// Represents a connected region of deferred basic blocks.
class DeferredBlocksRegion final {
public:
explicit DeferredBlocksRegion(Zone* zone)
: spilled_vregs_(zone), blocks_covered_(zone) {}
void AddBlock(RpoNumber block, MidTierRegisterAllocationData* data) {
DCHECK(data->GetBlock(block)->IsDeferred());
blocks_covered_.Add(block.ToInt());
data->block_state(block).set_deferred_blocks_region(this);
}
// Trys to adds |vreg| to the list of variables to potentially defer their
// output to a spill slot until we enter this deferred block region. Returns
// true if successful.
bool TryDeferSpillOutputUntilEntry(int vreg) {
if (spilled_vregs_.count(vreg) != 0) return true;
if (is_frozen_) return false;
spilled_vregs_.insert(vreg);
return true;
}
void FreezeDeferredSpills() { is_frozen_ = true; }
ZoneSet<int>::const_iterator begin() const { return spilled_vregs_.begin(); }
ZoneSet<int>::const_iterator end() const { return spilled_vregs_.end(); }
const SparseBitVector* blocks_covered() const { return &blocks_covered_; }
private:
ZoneSet<int> spilled_vregs_;
SparseBitVector blocks_covered_;
bool is_frozen_ = false;
};
// VirtualRegisterData stores data specific to a particular virtual register,
// and tracks spilled operands for that virtual register.
class VirtualRegisterData final {
@ -335,20 +217,7 @@ class VirtualRegisterData final {
void ExtendRangeTo(int instr_index) { live_range_.AddInstr(instr_index); }
void AddDeferredSpillOutput(AllocatedOperand allocated_op, int instr_index,
MidTierRegisterAllocationData* data) {
if (deferred_spill_outputs_ == nullptr) {
Zone* zone = data->allocation_zone();
deferred_spill_outputs_ =
zone->New<ZoneVector<DeferredSpillSlotOutput>>(zone);
}
const InstructionBlock* block = data->GetBlock(instr_index);
DCHECK_EQ(block->first_instruction_index(), instr_index);
BlockState& block_state = data->block_state(block->rpo_number());
const SparseBitVector* deferred_blocks =
block_state.deferred_blocks_region()->blocks_covered();
deferred_spill_outputs_->emplace_back(instr_index, allocated_op,
deferred_blocks);
}
MidTierRegisterAllocationData* data);
void ClearDeferredBlockSpills() { deferred_spill_outputs_ = nullptr; }
bool HasDeferredBlockSpills() const {
@ -399,6 +268,124 @@ class VirtualRegisterData final {
bool is_exceptional_call_output_ : 1;
};
// BlockState stores details associated with a particular basic block.
class BlockState final {
public:
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(BlockState);
explicit BlockState(Zone* zone) : dominated_blocks_(zone) {}
// Returns the RegisterState that applies to the input of this block. Can be
// |nullptr| if the no registers of |kind| have been allocated up to this
// point.
RegisterState* register_in_state(RegisterKind kind);
void set_register_in_state(RegisterState* register_state, RegisterKind kind);
// Returns a bitvector representing all the basic blocks that are dominated
// by this basic block.
SparseBitVector* dominated_blocks() { return &dominated_blocks_; }
// Set / get this block's index for successor's phi operations. Will return
// -1 if this block has no successor's with phi operations.
int successors_phi_index() const { return successors_phi_index_; }
void set_successors_phi_index(int index) {
DCHECK_EQ(successors_phi_index_, -1);
successors_phi_index_ = index;
}
// If this block is deferred, this represents region of deferred blocks
// that are directly reachable from this block.
DeferredBlocksRegion* deferred_blocks_region() const {
return deferred_blocks_region_;
}
void set_deferred_blocks_region(DeferredBlocksRegion* region) {
DCHECK_NULL(deferred_blocks_region_);
deferred_blocks_region_ = region;
}
// Returns true if this block represents either a transition from
// non-deferred to deferred or vice versa.
bool is_deferred_block_boundary() const {
return is_deferred_block_boundary_;
}
void MarkAsDeferredBlockBoundary() { is_deferred_block_boundary_ = true; }
private:
RegisterState* general_registers_in_state_ = nullptr;
RegisterState* double_registers_in_state_ = nullptr;
RegisterState* simd128_registers_in_state_ = nullptr;
DeferredBlocksRegion* deferred_blocks_region_ = nullptr;
SparseBitVector dominated_blocks_;
int successors_phi_index_ = -1;
bool is_deferred_block_boundary_ = false;
};
// Represents a connected region of deferred basic blocks.
class DeferredBlocksRegion final {
public:
explicit DeferredBlocksRegion(Zone* zone)
: spilled_vregs_(zone), blocks_covered_(zone) {}
void AddBlock(RpoNumber block, MidTierRegisterAllocationData* data) {
DCHECK(data->GetBlock(block)->IsDeferred());
blocks_covered_.Add(block.ToInt());
data->block_state(block).set_deferred_blocks_region(this);
}
// Trys to adds |vreg| to the list of variables to potentially defer their
// output to a spill slot until we enter this deferred block region. Returns
// true if successful.
bool TryDeferSpillOutputUntilEntry(int vreg) {
if (spilled_vregs_.count(vreg) != 0) return true;
if (is_frozen_) return false;
spilled_vregs_.insert(vreg);
return true;
}
void FreezeDeferredSpills() { is_frozen_ = true; }
ZoneSet<int>::const_iterator begin() const { return spilled_vregs_.begin(); }
ZoneSet<int>::const_iterator end() const { return spilled_vregs_.end(); }
const SparseBitVector* blocks_covered() const { return &blocks_covered_; }
private:
ZoneSet<int> spilled_vregs_;
SparseBitVector blocks_covered_;
bool is_frozen_ = false;
};
RegisterState* BlockState::register_in_state(RegisterKind kind) {
switch (kind) {
case RegisterKind::kGeneral:
return general_registers_in_state_;
case RegisterKind::kDouble:
return double_registers_in_state_;
case RegisterKind::kSimd128:
return simd128_registers_in_state_;
}
}
void BlockState::set_register_in_state(RegisterState* register_state,
RegisterKind kind) {
switch (kind) {
case RegisterKind::kGeneral:
DCHECK_NULL(general_registers_in_state_);
general_registers_in_state_ = register_state;
break;
case RegisterKind::kDouble:
DCHECK_NULL(double_registers_in_state_);
double_registers_in_state_ = register_state;
break;
case RegisterKind::kSimd128:
DCHECK_NULL(simd128_registers_in_state_);
simd128_registers_in_state_ = register_state;
break;
}
}
MidTierRegisterAllocationData::MidTierRegisterAllocationData(
const RegisterConfiguration* config, Zone* zone, Frame* frame,
InstructionSequence* code, TickCounter* tick_counter,
@ -421,6 +408,23 @@ MidTierRegisterAllocationData::MidTierRegisterAllocationData(
}
}
void VirtualRegisterData::SpillRange::AddDeferredSpillOutput(
AllocatedOperand allocated_op, int instr_index,
MidTierRegisterAllocationData* data) {
if (deferred_spill_outputs_ == nullptr) {
Zone* zone = data->allocation_zone();
deferred_spill_outputs_ =
zone->New<ZoneVector<DeferredSpillSlotOutput>>(zone);
}
const InstructionBlock* block = data->GetBlock(instr_index);
DCHECK_EQ(block->first_instruction_index(), instr_index);
BlockState& block_state = data->block_state(block->rpo_number());
const SparseBitVector* deferred_blocks =
block_state.deferred_blocks_region()->blocks_covered();
deferred_spill_outputs_->emplace_back(instr_index, allocated_op,
deferred_blocks);
}
MoveOperands* MidTierRegisterAllocationData::AddGapMove(
int instr_index, Instruction::GapPosition position,
const InstructionOperand& from, const InstructionOperand& to) {