Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | |
|
rmcilroy
2016/05/26 10:24:53
2016
oth
2016/05/26 21:26:51
Done.
| |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "src/interpreter/bytecode-register-optimizer.h" | |
| 6 | |
| 7 namespace v8 { | |
| 8 namespace internal { | |
| 9 namespace interpreter { | |
| 10 | |
| 11 // A class for tracking the state of a register. In particular, it | |
| 12 // tracks whether one register is valuewise equivalent to another, and | |
| 13 // also whether a register is materialized in the bytecode stream. | |
| 14 class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject { | |
| 15 public: | |
| 16 RegisterInfo(Register reg, int equivalence_id, bool materialized) | |
| 17 : register_(reg), | |
| 18 equivalence_id_(equivalence_id), | |
| 19 materialized_(materialized), | |
| 20 next_(this), | |
| 21 prev_(this) {} | |
| 22 | |
| 23 void AddToEquivalenceSetOf(RegisterInfo* info); | |
| 24 void RemoveFromEquivalenceSet(); | |
| 25 bool IsOnlyEquivalent() const; | |
| 26 bool IsOnlyMaterializedEquivalent() const; | |
| 27 bool IsEquivalent(RegisterInfo* info) const; | |
| 28 | |
| 29 RegisterInfo* GetMaterializedEquivalent(); | |
| 30 RegisterInfo* GetMaterializedEquivalentOtherThan(Register reg); | |
| 31 RegisterInfo* GetMaterializationCandidate(); | |
|
rmcilroy
2016/05/26 10:24:52
I think these functions deserve a comment, particu
oth
2016/05/26 21:26:51
Done.
| |
| 32 | |
| 33 Register register_value() const { return register_; } | |
| 34 bool materialized() const { return materialized_; } | |
| 35 void set_materialized(bool materialized) { materialized_ = materialized; } | |
| 36 void set_equivalence_id(int equivalence_id) { | |
| 37 equivalence_id_ = equivalence_id; | |
| 38 } | |
| 39 int equivalence_id() const { return equivalence_id_; } | |
| 40 RegisterInfo* next() const { return next_; } | |
| 41 | |
| 42 private: | |
| 43 Register register_; | |
| 44 int equivalence_id_; | |
|
rmcilroy
2016/05/26 10:24:53
This should probably be an unsigned long, and mayb
oth
2016/05/26 21:26:50
Done.
| |
| 45 bool materialized_; | |
| 46 | |
| 47 // Equivalence set pointers. | |
| 48 RegisterInfo* next_; | |
| 49 RegisterInfo* prev_; | |
| 50 | |
| 51 DISALLOW_COPY_AND_ASSIGN(RegisterInfo); | |
| 52 }; | |
| 53 | |
| 54 void BytecodeRegisterOptimizer::RegisterInfo::AddToEquivalenceSetOf( | |
| 55 RegisterInfo* info) { | |
| 56 DCHECK(!IsEquivalent(info) && IsOnlyEquivalent()); | |
| 57 this->next_ = info->next_; | |
| 58 this->prev_ = info; | |
| 59 this->prev_->next_ = this; | |
| 60 this->next_->prev_ = this; | |
| 61 set_equivalence_id(info->equivalence_id()); | |
| 62 } | |
| 63 | |
| 64 void BytecodeRegisterOptimizer::RegisterInfo::RemoveFromEquivalenceSet() { | |
| 65 this->next_->prev_ = this->prev_; | |
| 66 this->prev_->next_ = this->next_; | |
| 67 this->next_ = this->prev_ = this; | |
| 68 } | |
| 69 | |
| 70 bool BytecodeRegisterOptimizer::RegisterInfo::IsOnlyEquivalent() const { | |
|
rmcilroy
2016/05/26 10:24:53
This name is a bit confusing to me, how about IsUn
oth
2016/05/26 21:26:51
Agreed. For readability, perhaps IsOnlyMemberOfEqu
rmcilroy
2016/05/27 09:18:58
SGTM, thanks.
| |
| 71 return this->next_ == this; | |
| 72 } | |
| 73 | |
| 74 bool BytecodeRegisterOptimizer::RegisterInfo::IsOnlyMaterializedEquivalent() | |
| 75 const { | |
| 76 DCHECK(materialized()); | |
| 77 | |
| 78 const RegisterInfo* visitor = this->next_; | |
| 79 while (visitor != this) { | |
| 80 if (visitor->materialized()) { | |
| 81 return false; | |
| 82 } | |
| 83 visitor = visitor->next_; | |
| 84 } | |
| 85 return true; | |
| 86 } | |
| 87 | |
| 88 bool BytecodeRegisterOptimizer::RegisterInfo::IsEquivalent( | |
| 89 RegisterInfo* info) const { | |
| 90 return equivalence_id() == info->equivalence_id(); | |
| 91 } | |
| 92 | |
| 93 BytecodeRegisterOptimizer::RegisterInfo* | |
| 94 BytecodeRegisterOptimizer::RegisterInfo::GetMaterializedEquivalent() { | |
| 95 RegisterInfo* visitor = this; | |
| 96 do { | |
| 97 if (visitor->materialized()) { | |
| 98 return visitor; | |
| 99 } | |
| 100 visitor = visitor->next_; | |
| 101 } while (visitor != this); | |
| 102 | |
| 103 return nullptr; | |
| 104 } | |
| 105 | |
| 106 BytecodeRegisterOptimizer::RegisterInfo* | |
| 107 BytecodeRegisterOptimizer::RegisterInfo::GetMaterializationCandidate() { | |
|
rmcilroy
2016/05/26 10:24:53
It is difficult to figure out what this function d
oth
2016/05/26 21:26:50
GetEquivalentToMaterialize()?
rmcilroy
2016/05/27 09:18:58
SGTM, thanks.
| |
| 108 DCHECK(this->materialized()); | |
| 109 RegisterInfo* visitor = this->next_; | |
| 110 Register best_reg; | |
|
rmcilroy
2016/05/26 10:24:53
unused
oth
2016/05/26 21:26:51
Done.
| |
| 111 RegisterInfo* best_info = nullptr; | |
| 112 while (visitor != this) { | |
| 113 if (visitor->materialized()) { | |
| 114 return nullptr; | |
| 115 } | |
| 116 if (best_info == nullptr || | |
| 117 visitor->register_value() < best_info->register_value()) { | |
| 118 best_info = visitor; | |
| 119 } | |
| 120 visitor = visitor->next_; | |
| 121 } | |
| 122 return best_info; | |
| 123 } | |
| 124 | |
| 125 BytecodeRegisterOptimizer::BytecodeRegisterOptimizer( | |
| 126 Zone* zone, TemporaryRegisterAllocator* register_allocator, | |
| 127 int parameter_count, int fixed_register_count, | |
| 128 BytecodePipelineStage* next_stage) | |
| 129 : accumulator_(Register::bytecode_array()), | |
|
rmcilroy
2016/05/26 10:24:52
We don't use bytecode_array in bytecode, but I won
oth
2016/05/26 21:26:51
Done.
It was implemented in this way to keep the
| |
| 130 temporary_base_(register_allocator->allocation_base()), | |
| 131 register_map_(zone), | |
| 132 equivalence_id_(0), | |
| 133 next_stage_(next_stage), | |
| 134 flushed_(false), | |
| 135 zone_(zone) { | |
| 136 register_allocator->set_observer(this); | |
| 137 | |
| 138 // Calculate offset so register index values can be mapped into | |
| 139 // a vector of register metadata. | |
| 140 if (parameter_count != 0) { | |
| 141 map_index_offset_ = | |
| 142 -Register::FromParameterIndex(0, parameter_count).index(); | |
| 143 } else { | |
| 144 map_index_offset_ = -accumulator_.index(); | |
|
rmcilroy
2016/05/26 10:24:53
Does this side ever get hit? We should always have
oth
2016/05/26 21:26:50
Yes, it gets hit in tests that craft bytecode.
Th
rmcilroy
2016/05/27 09:18:58
SG, thanks
| |
| 145 } | |
| 146 | |
| 147 // Initialize register map for parameters, locals, and the | |
| 148 // accumulator. | |
| 149 register_map_.resize(map_index_offset_ + | |
| 150 static_cast<size_t>(fixed_register_count)); | |
|
rmcilroy
2016/05/26 10:24:53
Isn't fixed_register_count the same (or less than)
oth
2016/05/26 21:26:50
Done.
| |
| 151 for (size_t i = 0; i < register_map_.size(); ++i) { | |
| 152 register_map_[i] = new (zone) | |
| 153 RegisterInfo(RegisterFromMapIndex(i), equivalence_id_++, true); | |
| 154 DCHECK_EQ(register_map_[i]->register_value().index(), | |
| 155 RegisterFromMapIndex(i).index()); | |
| 156 } | |
| 157 accumulator_info_ = GetRegisterInfo(accumulator_); | |
| 158 DCHECK(accumulator_info_->register_value() == accumulator_); | |
| 159 } | |
| 160 | |
| 161 void BytecodeRegisterOptimizer::FlushState() { | |
| 162 if (flushed_) { | |
| 163 return; | |
| 164 } | |
| 165 | |
| 166 // Materialize all live registers. | |
| 167 size_t count = register_map_.size(); | |
| 168 for (size_t i = 0; i < count; ++i) { | |
| 169 RegisterInfo* reg_info = register_map_[i]; | |
| 170 if (!reg_info->materialized() && !reg_info->IsOnlyEquivalent()) { | |
| 171 DCHECK(RegisterIsTemporary(reg_info->register_value()) || | |
| 172 reg_info->register_value() == accumulator_); | |
| 173 Materialize(reg_info); | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 // Break all existing equivalences. | |
| 178 for (size_t i = 0; i < count; ++i) { | |
| 179 RegisterInfo* reg_info = register_map_[i]; | |
| 180 if (!reg_info->IsOnlyEquivalent()) { | |
| 181 reg_info->RemoveFromEquivalenceSet(); | |
| 182 reg_info->set_equivalence_id(equivalence_id_++); | |
|
rmcilroy
2016/05/26 10:24:53
nit - move the setting of equivalence_id into Remo
oth
2016/05/26 21:26:50
Done.
| |
| 183 } | |
| 184 } | |
| 185 flushed_ = true; | |
| 186 } | |
| 187 | |
| 188 // override | |
| 189 void BytecodeRegisterOptimizer::FlushBasicBlock() { | |
| 190 FlushState(); | |
| 191 next_stage_->FlushBasicBlock(); | |
| 192 } | |
| 193 | |
| 194 // override | |
| 195 size_t BytecodeRegisterOptimizer::FlushForOffset() { | |
| 196 FlushState(); | |
| 197 return next_stage_->FlushForOffset(); | |
| 198 } | |
| 199 | |
| 200 void BytecodeRegisterOptimizer::EmitNopTakingSourcePosition( | |
| 201 BytecodeNode* node) { | |
| 202 BytecodeNode nop(Bytecode::kNop); | |
| 203 nop.source_info().Update(node->source_info()); | |
| 204 WriteToNextStage(&nop); | |
| 205 node->source_info().set_invalid(); | |
| 206 } | |
| 207 | |
| 208 // override | |
| 209 void BytecodeRegisterOptimizer::Write(BytecodeNode* node) { | |
| 210 flushed_ = false; | |
| 211 | |
| 212 // | |
| 213 // The logic for register to register transfer here emits Nops with the | |
| 214 // current source position. | |
|
rmcilroy
2016/05/26 10:24:53
I'm not sure what this adds anything beyond the tw
oth
2016/05/26 21:26:50
Done.
| |
| 215 // | |
| 216 // Transfers with observable registers as the destination will be | |
| 217 // immediately materialized so the source position information will | |
| 218 // be ordered correctly. | |
| 219 // | |
| 220 // Transfers without observable destination registers will initially | |
| 221 // be emitted as Nop's with the source position. They may, or may | |
| 222 // not, be materialized by the optimizer. However, the source | |
| 223 // position is not lost and being attachd to a Nop is fine as the | |
|
rmcilroy
2016/05/26 10:24:53
attached
oth
2016/05/26 21:26:51
Done.
| |
| 224 // destination register is not observable in the debugger. | |
| 225 // | |
| 226 switch (node->bytecode()) { | |
| 227 case Bytecode::kLdar: { | |
| 228 EmitNopTakingSourcePosition(node); | |
|
rmcilroy
2016/05/26 10:24:53
nit - move into DoLdar / DoStar / DoMov.
Optional
oth
2016/05/26 21:26:50
Done. Tried the experiment with the source positio
| |
| 229 DoLdar(node); | |
| 230 return; | |
| 231 } | |
| 232 case Bytecode::kStar: { | |
| 233 EmitNopTakingSourcePosition(node); | |
| 234 DoStar(node); | |
| 235 return; | |
| 236 } | |
| 237 case Bytecode::kMov: { | |
| 238 EmitNopTakingSourcePosition(node); | |
| 239 DoMov(node); | |
| 240 return; | |
| 241 } | |
| 242 default: | |
| 243 break; | |
| 244 } | |
| 245 | |
| 246 if (Bytecodes::IsJump(node->bytecode()) || | |
| 247 node->bytecode() == Bytecode::kDebugger) { | |
| 248 // The debugger can manipulate locals and parameters, flush | |
| 249 // everything before handing over to it. Similarly, all state must | |
| 250 // be flushed before emitting a jump due to how bytecode offsets | |
| 251 // for jumps are evaluated. | |
| 252 FlushState(); | |
| 253 WriteToNextStage(node); | |
| 254 return; | |
|
rmcilroy
2016/05/26 10:24:53
nit - just do the FlushState here and fall-through
oth
2016/05/26 21:26:51
Done.
| |
| 255 } | |
| 256 | |
| 257 PrepareOperands(node); | |
| 258 WriteToNextStage(node); | |
| 259 } | |
| 260 | |
| 261 void BytecodeRegisterOptimizer::WriteToNextStage(BytecodeNode* node) { | |
| 262 next_stage_->Write(node); | |
| 263 } | |
| 264 | |
| 265 void BytecodeRegisterOptimizer::OutputRegisterTransfer( | |
| 266 RegisterInfo* input_info, RegisterInfo* output_info) { | |
| 267 Register input = input_info->register_value(); | |
| 268 Register output = output_info->register_value(); | |
| 269 DCHECK_NE(input.index(), output.index()); | |
| 270 | |
| 271 if (input == accumulator_) { | |
| 272 uint32_t operand = static_cast<uint32_t>(output.ToOperand()); | |
| 273 OperandScale scale = Bytecodes::OperandSizesToScale(output.SizeOfOperand()); | |
| 274 BytecodeNode node(Bytecode::kStar, operand, scale); | |
| 275 WriteToNextStage(&node); | |
| 276 } else if (output == accumulator_) { | |
| 277 uint32_t operand = static_cast<uint32_t>(input.ToOperand()); | |
| 278 OperandScale scale = Bytecodes::OperandSizesToScale(input.SizeOfOperand()); | |
| 279 BytecodeNode node(Bytecode::kLdar, operand, scale); | |
| 280 WriteToNextStage(&node); | |
| 281 } else { | |
| 282 uint32_t operand0 = static_cast<uint32_t>(input.ToOperand()); | |
| 283 uint32_t operand1 = static_cast<uint32_t>(output.ToOperand()); | |
| 284 OperandScale scale = Bytecodes::OperandSizesToScale(input.SizeOfOperand(), | |
| 285 output.SizeOfOperand()); | |
| 286 BytecodeNode node(Bytecode::kMov, operand0, operand1, scale); | |
| 287 WriteToNextStage(&node); | |
| 288 } | |
| 289 } | |
| 290 | |
| 291 void BytecodeRegisterOptimizer::CreateMaterializedEquivalentIfRequired( | |
| 292 RegisterInfo* info) { | |
| 293 if (info->materialized()) { | |
| 294 RegisterInfo* unmaterialized = info->GetMaterializationCandidate(); | |
| 295 if (unmaterialized) { | |
| 296 OutputRegisterTransfer(info, unmaterialized); | |
| 297 unmaterialized->set_materialized(true); | |
| 298 } | |
| 299 } | |
| 300 } | |
| 301 | |
| 302 BytecodeRegisterOptimizer::RegisterInfo* | |
| 303 BytecodeRegisterOptimizer::GetMaterializedEquivalent(RegisterInfo* info) { | |
| 304 return info->materialized() ? info : info->GetMaterializedEquivalent(); | |
| 305 } | |
| 306 | |
| 307 BytecodeRegisterOptimizer::RegisterInfo* | |
| 308 BytecodeRegisterOptimizer::GetMaterializedEquivalentNotAccumulator( | |
| 309 RegisterInfo* info) { | |
| 310 if (info->materialized()) { | |
| 311 return info; | |
| 312 } | |
| 313 | |
| 314 RegisterInfo* result = info->GetMaterializedEquivalent(); | |
|
rmcilroy
2016/05/26 10:24:53
Maybe just add an option to GetMaterializedEquival
oth
2016/05/26 21:26:51
Done.
| |
| 315 if (result->register_value() == accumulator_) { | |
| 316 result = result->next()->GetMaterializedEquivalent(); | |
| 317 if (result->register_value() == accumulator_) { | |
| 318 Materialize(info); | |
| 319 result = info; | |
| 320 } | |
| 321 } | |
| 322 return result; | |
| 323 } | |
| 324 | |
| 325 void BytecodeRegisterOptimizer::Materialize(RegisterInfo* info) { | |
| 326 if (!info->materialized()) { | |
| 327 RegisterInfo* materialized = info->GetMaterializedEquivalent(); | |
| 328 OutputRegisterTransfer(materialized, info); | |
| 329 info->set_materialized(true); | |
| 330 } | |
| 331 } | |
| 332 | |
| 333 void BytecodeRegisterOptimizer::RegisterTransfer(RegisterInfo* input_info, | |
| 334 RegisterInfo* output_info) { | |
| 335 // Ensure value associated with output is materialized into a | |
| 336 // different register if necessary. | |
| 337 CreateMaterializedEquivalentIfRequired(output_info); | |
| 338 bool output_is_observable = | |
| 339 RegisterIsObservable(output_info->register_value()); | |
| 340 | |
| 341 // If the output and input are not equivalent or the output is | |
| 342 // visible to the user/debugger, update equivalence set and | |
| 343 // potentially emit store if the transfer is observable. | |
| 344 if (!output_info->IsEquivalent(input_info) || output_is_observable) { | |
| 345 // Remove from current set and invalidate equivalence id. | |
| 346 output_info->RemoveFromEquivalenceSet(); | |
| 347 output_info->set_equivalence_id(equivalence_id_++); | |
| 348 | |
| 349 // Add to the equivalence set of |input_info|. | |
| 350 RegisterInfo* materialized_info = input_info->GetMaterializedEquivalent(); | |
| 351 output_info->AddToEquivalenceSetOf(materialized_info); | |
| 352 output_info->set_materialized(output_is_observable); | |
| 353 if (output_is_observable) { | |
| 354 OutputRegisterTransfer(materialized_info, output_info); | |
|
rmcilroy
2016/05/26 10:24:53
output_info should be set_materialized(true) shoul
oth
2016/05/26 21:26:51
Re-worked hopefully easier to reason about now ?
rmcilroy
2016/05/27 09:18:58
Looks good, thanks
| |
| 355 } | |
| 356 } | |
| 357 } | |
| 358 | |
| 359 void BytecodeRegisterOptimizer::DoLdar(const BytecodeNode* const node) { | |
| 360 Register input = GetRegisterInputOperand( | |
| 361 0, node->bytecode(), node->operands(), node->operand_count()); | |
| 362 RegisterInfo* input_info = GetRegisterInfo(input); | |
| 363 RegisterTransfer(input_info, accumulator_info_); | |
| 364 } | |
| 365 | |
| 366 void BytecodeRegisterOptimizer::DoMov(const BytecodeNode* const node) { | |
| 367 Register input = GetRegisterInputOperand( | |
| 368 0, node->bytecode(), node->operands(), node->operand_count()); | |
| 369 RegisterInfo* input_info = GetRegisterInfo(input); | |
| 370 Register output = GetRegisterOutputOperand( | |
| 371 1, node->bytecode(), node->operands(), node->operand_count()); | |
| 372 RegisterInfo* output_info = GetOrCreateRegisterInfo(output); | |
| 373 RegisterTransfer(input_info, output_info); | |
| 374 } | |
| 375 | |
| 376 void BytecodeRegisterOptimizer::DoStar(const BytecodeNode* const node) { | |
| 377 Register output = GetRegisterOutputOperand( | |
| 378 0, node->bytecode(), node->operands(), node->operand_count()); | |
| 379 RegisterInfo* output_info = GetOrCreateRegisterInfo(output); | |
| 380 RegisterTransfer(accumulator_info_, output_info); | |
| 381 } | |
| 382 | |
| 383 void BytecodeRegisterOptimizer::PrepareRegisterOutputOperand( | |
| 384 RegisterInfo* reg_info) { | |
| 385 CreateMaterializedEquivalentIfRequired(reg_info); | |
| 386 | |
| 387 // Put register in it's own equivalence set. | |
| 388 reg_info->RemoveFromEquivalenceSet(); | |
| 389 reg_info->set_materialized(true); | |
| 390 reg_info->set_equivalence_id(equivalence_id_++); | |
| 391 } | |
| 392 | |
| 393 void BytecodeRegisterOptimizer::PrepareRegisterRangeOutputOperand( | |
| 394 Register start, int count) { | |
| 395 for (int i = 0; i < count; ++i) { | |
| 396 Register reg(start.index() + i); | |
| 397 RegisterInfo* reg_info = GetOrCreateRegisterInfo(reg); | |
| 398 PrepareRegisterOutputOperand(reg_info); | |
| 399 } | |
| 400 } | |
| 401 | |
| 402 Register BytecodeRegisterOptimizer::PrepareRegisterInputOperand(Register reg) { | |
| 403 RegisterInfo* reg_info = GetOrCreateRegisterInfo(reg); | |
|
rmcilroy
2016/05/26 10:24:53
Reginfo should be create here shouldn't it? Just G
oth
2016/05/26 21:26:51
Comment added. The create case is for the first ti
| |
| 404 if (reg_info->materialized()) { | |
| 405 return reg; | |
| 406 } else { | |
| 407 RegisterInfo* equivalent_info = | |
| 408 GetMaterializedEquivalentNotAccumulator(reg_info); | |
| 409 return equivalent_info->register_value(); | |
| 410 } | |
| 411 } | |
| 412 | |
| 413 void BytecodeRegisterOptimizer::PrepareRegisterRangeInputOperand(Register start, | |
| 414 int count) { | |
| 415 for (int i = 0; i < count; ++i) { | |
| 416 Register current(start.index() + i); | |
| 417 RegisterInfo* input_info = GetRegisterInfo(current); | |
| 418 Materialize(input_info); | |
| 419 } | |
| 420 } | |
| 421 | |
| 422 void BytecodeRegisterOptimizer::PrepareRegisterOperands( | |
| 423 BytecodeNode* const node) { | |
| 424 // | |
| 425 // For each input operand, get a materialized equivalent if it is | |
| 426 // just a single register, otherwise materialize register range. | |
| 427 // Update operand_scale if necessary. | |
| 428 // | |
| 429 // For each output register about to be clobbered, materialize an | |
| 430 // equivalent if it exists. Put each register in it's own equivalence set. | |
| 431 // | |
| 432 int register_operand_bitmap = | |
| 433 Bytecodes::GetRegisterOperandBitmap(node->bytecode()); | |
| 434 const OperandType* operand_types = | |
| 435 Bytecodes::GetOperandTypes(node->bytecode()); | |
| 436 uint32_t* operands = node->operands(); | |
| 437 for (int i = 0; register_operand_bitmap != 0; | |
| 438 ++i, register_operand_bitmap >>= 1) { | |
| 439 if ((register_operand_bitmap & 1) == 0) { | |
| 440 continue; | |
| 441 } | |
| 442 OperandType operand_type = operand_types[i]; | |
| 443 int count = 0; | |
| 444 if (operand_types[i + 1] == OperandType::kRegCount) { | |
|
rmcilroy
2016/05/26 10:24:53
This is repeated in a bunch of places (e.g., bytec
oth
2016/05/26 21:26:51
This is a little bit raw. If it's a helper, it'll
| |
| 445 count = static_cast<int>(operands[i + 1]); | |
| 446 if (count == 0) { | |
| 447 continue; | |
| 448 } | |
| 449 } else { | |
| 450 count = Bytecodes::GetNumberOfRegistersRepresentedBy(operand_type); | |
| 451 } | |
| 452 | |
| 453 Register reg = Register::FromOperand(static_cast<int32_t>(operands[i])); | |
| 454 if (Bytecodes::IsRegisterInputOperandType(operand_type)) { | |
| 455 if (count == 1) { | |
| 456 Register equivalent = PrepareRegisterInputOperand(reg); | |
|
rmcilroy
2016/05/26 10:24:53
PrepareRegisterInputOperand does something differe
oth
2016/05/26 21:26:50
Done.
| |
| 457 operands[i] = static_cast<uint32_t>(equivalent.ToOperand()); | |
| 458 // Update operand scale as equivalent may be different. | |
| 459 OperandScale operand_scale = | |
| 460 Bytecodes::OperandSizesToScale(equivalent.SizeOfOperand()); | |
| 461 if (operand_scale > node->operand_scale()) { | |
| 462 node->set_operand_scale(operand_scale); | |
| 463 } | |
| 464 } else if (count > 1) { | |
| 465 PrepareRegisterRangeInputOperand(reg, count); | |
| 466 } | |
| 467 } else if (Bytecodes::IsRegisterOutputOperandType(operand_type)) { | |
| 468 PrepareRegisterRangeOutputOperand(reg, count); | |
| 469 } | |
| 470 } | |
| 471 } | |
| 472 | |
| 473 void BytecodeRegisterOptimizer::PrepareAccumulator(BytecodeNode* const node) { | |
| 474 // Materialize the accumulator if it is read by the bytecode. The | |
| 475 // accumulator is special and no other register can be materialized | |
| 476 // in it's place. | |
| 477 if (Bytecodes::ReadsAccumulator(node->bytecode()) && | |
| 478 !accumulator_info_->materialized()) { | |
| 479 Materialize(accumulator_info_); | |
| 480 } | |
| 481 | |
| 482 // Materialize an equivalent to the accumulator if it will be | |
| 483 // clobbered when the bytecode is dispatched. | |
| 484 if (Bytecodes::WritesAccumulator(node->bytecode())) { | |
| 485 PrepareRegisterOutputOperand(accumulator_info_); | |
| 486 } | |
| 487 } | |
| 488 | |
| 489 void BytecodeRegisterOptimizer::PrepareOperands(BytecodeNode* const node) { | |
| 490 PrepareAccumulator(node); | |
| 491 PrepareRegisterOperands(node); | |
| 492 } | |
| 493 | |
| 494 // static | |
| 495 Register BytecodeRegisterOptimizer::GetRegisterInputOperand( | |
| 496 int index, Bytecode bytecode, const uint32_t* operands, int operand_count) { | |
| 497 DCHECK_LT(index, operand_count); | |
| 498 DCHECK(Bytecodes::IsRegisterInputOperandType( | |
| 499 Bytecodes::GetOperandType(bytecode, index))); | |
| 500 return OperandToRegister(operands[index]); | |
| 501 } | |
| 502 | |
| 503 // static | |
| 504 Register BytecodeRegisterOptimizer::GetRegisterOutputOperand( | |
| 505 int index, Bytecode bytecode, const uint32_t* operands, int operand_count) { | |
| 506 DCHECK_LT(index, operand_count); | |
| 507 DCHECK(Bytecodes::IsRegisterOutputOperandType( | |
| 508 Bytecodes::GetOperandType(bytecode, index))); | |
| 509 return OperandToRegister(operands[index]); | |
| 510 } | |
| 511 | |
| 512 BytecodeRegisterOptimizer::RegisterInfo* | |
| 513 BytecodeRegisterOptimizer::GetRegisterInfo(Register reg) { | |
| 514 size_t index = GetMapIndex(reg); | |
| 515 return (index < register_map_.size()) ? register_map_[index] : nullptr; | |
|
rmcilroy
2016/05/26 10:24:53
it looks like we always depend on this returning n
oth
2016/05/26 21:26:50
This can be called from TemporaryRegisterFreeEvent
rmcilroy
2016/05/27 09:18:58
OK sounds good, thanks.
| |
| 516 } | |
| 517 | |
| 518 BytecodeRegisterOptimizer::RegisterInfo* | |
| 519 BytecodeRegisterOptimizer::GetOrCreateRegisterInfo(Register reg) { | |
| 520 size_t index = GetMapIndex(reg); | |
| 521 return index < register_map_.size() ? register_map_[index] | |
| 522 : NewRegisterInfo(reg); | |
| 523 } | |
| 524 | |
| 525 BytecodeRegisterOptimizer::RegisterInfo* | |
| 526 BytecodeRegisterOptimizer::NewRegisterInfo(Register reg) { | |
| 527 size_t index = GetMapIndex(reg); | |
| 528 DCHECK_GE(index, register_map_.size()); | |
| 529 GrowRegisterMap(reg); | |
| 530 return register_map_[index]; | |
| 531 } | |
| 532 | |
| 533 void BytecodeRegisterOptimizer::GrowRegisterMap(Register reg) { | |
| 534 DCHECK(RegisterIsTemporary(reg)); | |
| 535 size_t index = GetMapIndex(reg); | |
| 536 DCHECK_GE(index, register_map_.size()); | |
| 537 size_t new_size = index + 1; | |
| 538 size_t old_size = register_map_.size(); | |
| 539 register_map_.resize(new_size); | |
| 540 for (size_t i = old_size; i < new_size; ++i) { | |
| 541 register_map_[i] = new (zone()) | |
| 542 RegisterInfo(RegisterFromMapIndex(i), equivalence_id_++, false); | |
| 543 } | |
| 544 } | |
| 545 | |
| 546 void BytecodeRegisterOptimizer::TemporaryRegisterFreeEvent(Register reg) { | |
| 547 RegisterInfo* info = GetRegisterInfo(reg); | |
| 548 if (info != nullptr) { | |
| 549 // If register is materialized and part of equivalence set, make | |
| 550 // sure another member of the set holds the value before the | |
| 551 // temporary register is removed. | |
| 552 CreateMaterializedEquivalentIfRequired(info); | |
| 553 info->RemoveFromEquivalenceSet(); | |
| 554 info->set_materialized(false); | |
| 555 info->set_equivalence_id(-1); | |
| 556 } | |
| 557 } | |
| 558 | |
| 559 } // namespace interpreter | |
| 560 } // namespace internal | |
| 561 } // namespace v8 | |
| OLD | NEW |