5 #include "src/interpreter/bytecode-register-optimizer.h" 9 namespace interpreter {
11 const uint32_t BytecodeRegisterOptimizer::kInvalidEquivalenceId = kMaxUInt32;
21 equivalence_id_(equivalence_id),
22 materialized_(materialized),
23 allocated_(allocated),
29 void MoveToNewEquivalenceSet(
uint32_t equivalence_id,
bool materialized);
30 bool IsOnlyMemberOfEquivalenceSet()
const;
31 bool IsOnlyMaterializedMemberOfEquivalenceSet()
const;
60 void MarkTemporariesAsUnmaterialized(
Register temporary_base);
65 Register register_value()
const {
return register_; }
66 bool materialized()
const {
return materialized_; }
67 void set_materialized(
bool materialized) { materialized_ = materialized; }
68 bool allocated()
const {
return allocated_; }
69 void set_allocated(
bool allocated) { allocated_ = allocated; }
70 void set_equivalence_id(
uint32_t equivalence_id) {
71 equivalence_id_ = equivalence_id;
73 uint32_t equivalence_id()
const {
return equivalence_id_; }
75 bool needs_flush()
const {
return needs_flush_; }
76 void set_needs_flush(
bool needs_flush) { needs_flush_ = needs_flush; }
92 void BytecodeRegisterOptimizer::RegisterInfo::AddToEquivalenceSetOf(
94 DCHECK_NE(kInvalidEquivalenceId, info->equivalence_id());
103 set_equivalence_id(info->equivalence_id());
104 set_materialized(
false);
107 void BytecodeRegisterOptimizer::RegisterInfo::MoveToNewEquivalenceSet(
108 uint32_t equivalence_id,
bool materialized) {
109 next_->prev_ = prev_;
110 prev_->next_ = next_;
111 next_ = prev_ =
this;
112 equivalence_id_ = equivalence_id;
113 materialized_ = materialized;
116 bool BytecodeRegisterOptimizer::RegisterInfo::IsOnlyMemberOfEquivalenceSet()
118 return this->next_ ==
this;
121 bool BytecodeRegisterOptimizer::RegisterInfo::
122 IsOnlyMaterializedMemberOfEquivalenceSet()
const {
123 DCHECK(materialized());
125 const RegisterInfo* visitor = this->next_;
126 while (visitor !=
this) {
127 if (visitor->materialized()) {
130 visitor = visitor->next_;
135 bool BytecodeRegisterOptimizer::RegisterInfo::IsInSameEquivalenceSet(
136 RegisterInfo* info)
const {
137 return equivalence_id() == info->equivalence_id();
140 BytecodeRegisterOptimizer::RegisterInfo*
141 BytecodeRegisterOptimizer::RegisterInfo::GetAllocatedEquivalent() {
142 RegisterInfo* visitor =
this;
144 if (visitor->allocated()) {
147 visitor = visitor->next_;
148 }
while (visitor !=
this);
153 BytecodeRegisterOptimizer::RegisterInfo*
154 BytecodeRegisterOptimizer::RegisterInfo::GetMaterializedEquivalent() {
155 RegisterInfo* visitor =
this;
157 if (visitor->materialized()) {
160 visitor = visitor->next_;
161 }
while (visitor !=
this);
166 BytecodeRegisterOptimizer::RegisterInfo*
167 BytecodeRegisterOptimizer::RegisterInfo::GetMaterializedEquivalentOtherThan(
169 RegisterInfo* visitor =
this;
171 if (visitor->materialized() && visitor->register_value() != reg) {
174 visitor = visitor->next_;
175 }
while (visitor !=
this);
180 BytecodeRegisterOptimizer::RegisterInfo*
181 BytecodeRegisterOptimizer::RegisterInfo::GetEquivalentToMaterialize() {
182 DCHECK(this->materialized());
183 RegisterInfo* visitor = this->next_;
184 RegisterInfo* best_info =
nullptr;
185 while (visitor !=
this) {
186 if (visitor->materialized()) {
189 if (visitor->allocated() &&
190 (best_info ==
nullptr ||
191 visitor->register_value() < best_info->register_value())) {
194 visitor = visitor->next_;
199 void BytecodeRegisterOptimizer::RegisterInfo::MarkTemporariesAsUnmaterialized(
200 Register temporary_base) {
201 DCHECK(this->register_value() < temporary_base);
202 DCHECK(this->materialized());
203 RegisterInfo* visitor = this->next_;
204 while (visitor !=
this) {
205 if (visitor->register_value() >= temporary_base) {
206 visitor->set_materialized(
false);
208 visitor = visitor->next_;
212 BytecodeRegisterOptimizer::RegisterInfo*
213 BytecodeRegisterOptimizer::RegisterInfo::GetEquivalent() {
217 BytecodeRegisterOptimizer::BytecodeRegisterOptimizer(
218 Zone* zone, BytecodeRegisterAllocator* register_allocator,
219 int fixed_registers_count,
int parameter_count,
220 BytecodeWriter* bytecode_writer)
221 : accumulator_(Register::virtual_accumulator()),
222 temporary_base_(fixed_registers_count),
223 max_register_index_(fixed_registers_count - 1),
224 register_info_table_(zone),
225 registers_needing_flushed_(zone),
227 bytecode_writer_(bytecode_writer),
228 flush_required_(false),
230 register_allocator->set_observer(
this);
235 DCHECK_NE(parameter_count, 0);
236 register_info_table_offset_ =
237 -Register::FromParameterIndex(0, parameter_count).index();
241 register_info_table_.resize(register_info_table_offset_ +
242 static_cast<size_t>(temporary_base_.index()));
243 for (
size_t i = 0;
i < register_info_table_.size(); ++
i) {
244 register_info_table_[
i] =
new (zone) RegisterInfo(
245 RegisterFromRegisterInfoTableIndex(
i), NextEquivalenceId(),
true,
true);
246 DCHECK_EQ(register_info_table_[
i]->register_value().index(),
247 RegisterFromRegisterInfoTableIndex(
i).index());
249 accumulator_info_ = GetRegisterInfo(accumulator_);
250 DCHECK(accumulator_info_->register_value() == accumulator_);
253 void BytecodeRegisterOptimizer::PushToRegistersNeedingFlush(RegisterInfo* reg) {
254 if (!reg->needs_flush()) {
255 reg->set_needs_flush(
true);
256 registers_needing_flushed_.push_back(reg);
260 bool BytecodeRegisterOptimizer::EnsureAllRegistersAreFlushed()
const {
261 for (RegisterInfo* reg_info : register_info_table_) {
262 if (reg_info->needs_flush()) {
264 }
else if (!reg_info->IsOnlyMemberOfEquivalenceSet()) {
266 }
else if (reg_info->allocated() && !reg_info->materialized()) {
273 void BytecodeRegisterOptimizer::Flush() {
274 if (!flush_required_) {
279 for (RegisterInfo* reg_info : registers_needing_flushed_) {
280 if (!reg_info->needs_flush())
continue;
281 reg_info->set_needs_flush(
false);
283 RegisterInfo* materialized = reg_info->materialized()
285 : reg_info->GetMaterializedEquivalent();
287 if (materialized !=
nullptr) {
291 RegisterInfo* equivalent;
292 while ((equivalent = materialized->GetEquivalent()) != materialized) {
293 if (equivalent->allocated() && !equivalent->materialized()) {
294 OutputRegisterTransfer(materialized, equivalent);
296 equivalent->MoveToNewEquivalenceSet(NextEquivalenceId(),
true);
297 equivalent->set_needs_flush(
false);
301 DCHECK_NULL(reg_info->GetAllocatedEquivalent());
302 reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(),
false);
306 registers_needing_flushed_.clear();
307 DCHECK(EnsureAllRegistersAreFlushed());
309 flush_required_ =
false;
312 void BytecodeRegisterOptimizer::OutputRegisterTransfer(
313 RegisterInfo* input_info, RegisterInfo* output_info) {
314 Register input = input_info->register_value();
315 Register output = output_info->register_value();
316 DCHECK_NE(input.index(), output.index());
318 if (input == accumulator_) {
319 bytecode_writer_->EmitStar(output);
320 }
else if (output == accumulator_) {
321 bytecode_writer_->EmitLdar(input);
323 bytecode_writer_->EmitMov(input, output);
325 if (output != accumulator_) {
326 max_register_index_ = std::max(max_register_index_, output.index());
328 output_info->set_materialized(
true);
331 void BytecodeRegisterOptimizer::CreateMaterializedEquivalent(
332 RegisterInfo* info) {
333 DCHECK(info->materialized());
334 RegisterInfo* unmaterialized = info->GetEquivalentToMaterialize();
335 if (unmaterialized) {
336 OutputRegisterTransfer(info, unmaterialized);
340 BytecodeRegisterOptimizer::RegisterInfo*
341 BytecodeRegisterOptimizer::GetMaterializedEquivalent(RegisterInfo* info) {
342 return info->materialized() ? info : info->GetMaterializedEquivalent();
345 BytecodeRegisterOptimizer::RegisterInfo*
346 BytecodeRegisterOptimizer::GetMaterializedEquivalentNotAccumulator(
347 RegisterInfo* info) {
348 if (info->materialized()) {
352 RegisterInfo* result = info->GetMaterializedEquivalentOtherThan(accumulator_);
353 if (result ==
nullptr) {
357 DCHECK(result->register_value() != accumulator_);
361 void BytecodeRegisterOptimizer::Materialize(RegisterInfo* info) {
362 if (!info->materialized()) {
363 RegisterInfo* materialized = info->GetMaterializedEquivalent();
364 DCHECK_NOT_NULL(materialized);
365 OutputRegisterTransfer(materialized, info);
369 void BytecodeRegisterOptimizer::AddToEquivalenceSet(
370 RegisterInfo* set_member, RegisterInfo* non_set_member) {
372 PushToRegistersNeedingFlush(non_set_member);
373 non_set_member->AddToEquivalenceSetOf(set_member);
376 flush_required_ =
true;
379 void BytecodeRegisterOptimizer::RegisterTransfer(RegisterInfo* input_info,
380 RegisterInfo* output_info) {
381 bool output_is_observable =
382 RegisterIsObservable(output_info->register_value());
383 bool in_same_equivalence_set =
384 output_info->IsInSameEquivalenceSet(input_info);
385 if (in_same_equivalence_set &&
386 (!output_is_observable || output_info->materialized())) {
392 if (output_info->materialized()) {
393 CreateMaterializedEquivalent(output_info);
397 if (!in_same_equivalence_set) {
398 AddToEquivalenceSet(input_info, output_info);
401 if (output_is_observable) {
403 output_info->set_materialized(
false);
404 RegisterInfo* materialized_info = input_info->GetMaterializedEquivalent();
405 OutputRegisterTransfer(materialized_info, output_info);
408 bool input_is_observable = RegisterIsObservable(input_info->register_value());
409 if (input_is_observable) {
412 input_info->MarkTemporariesAsUnmaterialized(temporary_base_);
416 void BytecodeRegisterOptimizer::PrepareOutputRegister(Register reg) {
417 RegisterInfo* reg_info = GetRegisterInfo(reg);
418 if (reg_info->materialized()) {
419 CreateMaterializedEquivalent(reg_info);
421 reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(),
true);
422 max_register_index_ =
423 std::max(max_register_index_, reg_info->register_value().index());
426 void BytecodeRegisterOptimizer::PrepareOutputRegisterList(
427 RegisterList reg_list) {
428 int start_index = reg_list.first_register().index();
429 for (
int i = 0;
i < reg_list.register_count(); ++
i) {
430 Register current(start_index +
i);
431 PrepareOutputRegister(current);
435 Register BytecodeRegisterOptimizer::GetInputRegister(Register reg) {
436 RegisterInfo* reg_info = GetRegisterInfo(reg);
437 if (reg_info->materialized()) {
440 RegisterInfo* equivalent_info =
441 GetMaterializedEquivalentNotAccumulator(reg_info);
442 return equivalent_info->register_value();
446 RegisterList BytecodeRegisterOptimizer::GetInputRegisterList(
447 RegisterList reg_list) {
448 if (reg_list.register_count() == 1) {
450 Register reg(GetInputRegister(reg_list.first_register()));
451 return RegisterList(reg);
453 int start_index = reg_list.first_register().index();
454 for (
int i = 0;
i < reg_list.register_count(); ++
i) {
455 Register current(start_index +
i);
456 RegisterInfo* input_info = GetRegisterInfo(current);
457 Materialize(input_info);
463 void BytecodeRegisterOptimizer::GrowRegisterMap(Register reg) {
464 DCHECK(RegisterIsTemporary(reg));
465 size_t index = GetRegisterInfoTableIndex(reg);
466 if (index >= register_info_table_.size()) {
467 size_t new_size = index + 1;
468 size_t old_size = register_info_table_.size();
469 register_info_table_.resize(new_size);
470 for (
size_t i = old_size;
i < new_size; ++
i) {
471 register_info_table_[
i] =
472 new (zone()) RegisterInfo(RegisterFromRegisterInfoTableIndex(
i),
473 NextEquivalenceId(),
true,
false);
478 void BytecodeRegisterOptimizer::AllocateRegister(RegisterInfo* info) {
479 info->set_allocated(
true);
480 if (!info->materialized()) {
481 info->MoveToNewEquivalenceSet(NextEquivalenceId(),
true);
485 void BytecodeRegisterOptimizer::RegisterAllocateEvent(Register reg) {
486 AllocateRegister(GetOrCreateRegisterInfo(reg));
489 void BytecodeRegisterOptimizer::RegisterListAllocateEvent(
490 RegisterList reg_list) {
491 if (reg_list.register_count() != 0) {
492 int first_index = reg_list.first_register().index();
493 GrowRegisterMap(Register(first_index + reg_list.register_count() - 1));
494 for (
int i = 0;
i < reg_list.register_count();
i++) {
495 AllocateRegister(GetRegisterInfo(Register(first_index +
i)));
500 void BytecodeRegisterOptimizer::RegisterListFreeEvent(RegisterList reg_list) {
501 int first_index = reg_list.first_register().index();
502 for (
int i = 0;
i < reg_list.register_count();
i++) {
503 GetRegisterInfo(Register(first_index +
i))->set_allocated(
false);