• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 the V8 project authors. All rights reserved.
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/compiler/backend/mid-tier-register-allocator.h"
6 
7 #include <ostream>
8 
9 #include "src/base/bits.h"
10 #include "src/base/logging.h"
11 #include "src/base/macros.h"
12 #include "src/base/optional.h"
13 #include "src/codegen/machine-type.h"
14 #include "src/codegen/register-configuration.h"
15 #include "src/codegen/tick-counter.h"
16 #include "src/common/globals.h"
17 #include "src/compiler/backend/instruction.h"
18 #include "src/compiler/linkage.h"
19 #include "src/logging/counters.h"
20 #include "src/utils/bit-vector.h"
21 #include "src/zone/zone-containers.h"
22 
23 namespace v8 {
24 namespace internal {
25 namespace compiler {
26 
27 class RegisterState;
28 class DeferredBlocksRegion;
29 
30 // BlockState stores details associated with a particular basic block.
31 class BlockState final {
32  public:
BlockState(int block_count,Zone * zone)33   BlockState(int block_count, Zone* zone)
34       : general_registers_in_state_(nullptr),
35         double_registers_in_state_(nullptr),
36         deferred_blocks_region_(nullptr),
37         dominated_blocks_(block_count, zone),
38         successors_phi_index_(-1),
39         is_deferred_block_boundary_(false) {}
40 
41   // Returns the RegisterState that applies to the input of this block. Can be
42   // |nullptr| if the no registers of |kind| have been allocated up to this
43   // point.
44   RegisterState* register_in_state(RegisterKind kind);
45   void set_register_in_state(RegisterState* register_state, RegisterKind kind);
46 
47   // Returns a bitvector representing all the basic blocks that are dominated
48   // by this basic block.
dominated_blocks()49   BitVector* dominated_blocks() { return &dominated_blocks_; }
50 
51   // Set / get this block's index for successor's phi operations. Will return
52   // -1 if this block has no successor's with phi operations.
successors_phi_index() const53   int successors_phi_index() const { return successors_phi_index_; }
set_successors_phi_index(int index)54   void set_successors_phi_index(int index) {
55     DCHECK_EQ(successors_phi_index_, -1);
56     successors_phi_index_ = index;
57   }
58 
59   // If this block is deferred, this represents region of deferred blocks
60   // that are directly reachable from this block.
deferred_blocks_region() const61   DeferredBlocksRegion* deferred_blocks_region() const {
62     return deferred_blocks_region_;
63   }
set_deferred_blocks_region(DeferredBlocksRegion * region)64   void set_deferred_blocks_region(DeferredBlocksRegion* region) {
65     DCHECK_NULL(deferred_blocks_region_);
66     deferred_blocks_region_ = region;
67   }
68 
69   // Returns true if this block represents either a transition from
70   // non-deferred to deferred or vice versa.
is_deferred_block_boundary() const71   bool is_deferred_block_boundary() const {
72     return is_deferred_block_boundary_;
73   }
MarkAsDeferredBlockBoundary()74   void MarkAsDeferredBlockBoundary() { is_deferred_block_boundary_ = true; }
75 
76   MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(BlockState);
77 
78  private:
79   RegisterState* general_registers_in_state_;
80   RegisterState* double_registers_in_state_;
81   RegisterState* simd128_registers_in_state_;
82 
83   DeferredBlocksRegion* deferred_blocks_region_;
84 
85   BitVector dominated_blocks_;
86   int successors_phi_index_;
87   bool is_deferred_block_boundary_;
88 };
89 
register_in_state(RegisterKind kind)90 RegisterState* BlockState::register_in_state(RegisterKind kind) {
91   switch (kind) {
92     case RegisterKind::kGeneral:
93       return general_registers_in_state_;
94     case RegisterKind::kDouble:
95       return double_registers_in_state_;
96     case RegisterKind::kSimd128:
97       return simd128_registers_in_state_;
98   }
99 }
100 
set_register_in_state(RegisterState * register_state,RegisterKind kind)101 void BlockState::set_register_in_state(RegisterState* register_state,
102                                        RegisterKind kind) {
103   switch (kind) {
104     case RegisterKind::kGeneral:
105       DCHECK_NULL(general_registers_in_state_);
106       general_registers_in_state_ = register_state;
107       break;
108     case RegisterKind::kDouble:
109       DCHECK_NULL(double_registers_in_state_);
110       double_registers_in_state_ = register_state;
111       break;
112     case RegisterKind::kSimd128:
113       DCHECK_NULL(simd128_registers_in_state_);
114       simd128_registers_in_state_ = register_state;
115       break;
116   }
117 }
118 
MidTierRegisterAllocationData(const RegisterConfiguration * config,Zone * zone,Frame * frame,InstructionSequence * code,TickCounter * tick_counter,const char * debug_name)119 MidTierRegisterAllocationData::MidTierRegisterAllocationData(
120     const RegisterConfiguration* config, Zone* zone, Frame* frame,
121     InstructionSequence* code, TickCounter* tick_counter,
122     const char* debug_name)
123     : RegisterAllocationData(Type::kMidTier),
124       allocation_zone_(zone),
125       frame_(frame),
126       code_(code),
127       debug_name_(debug_name),
128       config_(config),
129       virtual_register_data_(code->VirtualRegisterCount(), allocation_zone()),
130       block_states_(allocation_zone()),
131       reference_map_instructions_(allocation_zone()),
132       spilled_virtual_registers_(code->VirtualRegisterCount(),
133                                  allocation_zone()),
134       tick_counter_(tick_counter) {
135   int basic_block_count = code->InstructionBlockCount();
136   block_states_.reserve(basic_block_count);
137   for (int i = 0; i < basic_block_count; i++) {
138     block_states_.emplace_back(basic_block_count, allocation_zone());
139   }
140 }
141 
AddGapMove(int instr_index,Instruction::GapPosition position,const InstructionOperand & from,const InstructionOperand & to)142 MoveOperands* MidTierRegisterAllocationData::AddGapMove(
143     int instr_index, Instruction::GapPosition position,
144     const InstructionOperand& from, const InstructionOperand& to) {
145   Instruction* instr = code()->InstructionAt(instr_index);
146   ParallelMove* moves = instr->GetOrCreateParallelMove(position, code_zone());
147   return moves->AddMove(from, to);
148 }
149 
AddPendingOperandGapMove(int instr_index,Instruction::GapPosition position)150 MoveOperands* MidTierRegisterAllocationData::AddPendingOperandGapMove(
151     int instr_index, Instruction::GapPosition position) {
152   return AddGapMove(instr_index, position, PendingOperand(), PendingOperand());
153 }
154 
block_state(RpoNumber rpo_number)155 BlockState& MidTierRegisterAllocationData::block_state(RpoNumber rpo_number) {
156   return block_states_[rpo_number.ToInt()];
157 }
158 
GetBlock(RpoNumber rpo_number)159 const InstructionBlock* MidTierRegisterAllocationData::GetBlock(
160     RpoNumber rpo_number) {
161   return code()->InstructionBlockAt(rpo_number);
162 }
163 
GetBlock(int instr_index)164 const InstructionBlock* MidTierRegisterAllocationData::GetBlock(
165     int instr_index) {
166   return code()->InstructionAt(instr_index)->block();
167 }
168 
GetBlocksDominatedBy(const InstructionBlock * block)169 const BitVector* MidTierRegisterAllocationData::GetBlocksDominatedBy(
170     const InstructionBlock* block) {
171   return block_state(block->rpo_number()).dominated_blocks();
172 }
173 
174 // RegisterIndex represents a particular register of a given kind (depending
175 // on the RegisterKind of the allocator).
176 class RegisterIndex final {
177  public:
RegisterIndex()178   RegisterIndex() : index_(kInvalidIndex) {}
RegisterIndex(int index)179   explicit RegisterIndex(int index) : index_(index) {}
Invalid()180   static RegisterIndex Invalid() { return RegisterIndex(); }
181 
is_valid() const182   bool is_valid() const { return index_ != kInvalidIndex; }
183 
ToInt() const184   int ToInt() const {
185     DCHECK(is_valid());
186     return index_;
187   }
188 
ToBit(MachineRepresentation rep) const189   uintptr_t ToBit(MachineRepresentation rep) const {
190     if (kFPAliasing != AliasingKind::kCombine ||
191         rep != MachineRepresentation::kSimd128) {
192       return 1ull << ToInt();
193     } else {
194       DCHECK_EQ(rep, MachineRepresentation::kSimd128);
195       return 3ull << ToInt();
196     }
197   }
198 
operator ==(const RegisterIndex & rhs) const199   bool operator==(const RegisterIndex& rhs) const {
200     return index_ == rhs.index_;
201   }
operator !=(const RegisterIndex & rhs) const202   bool operator!=(const RegisterIndex& rhs) const {
203     return index_ != rhs.index_;
204   }
205 
206   class Iterator {
207    public:
Iterator(int index)208     explicit Iterator(int index) : index_(index) {}
209 
operator !=(const Iterator & rhs) const210     bool operator!=(const Iterator& rhs) const { return index_ != rhs.index_; }
operator ++()211     void operator++() { index_++; }
operator *() const212     RegisterIndex operator*() const { return RegisterIndex(index_); }
213 
214    private:
215     int index_;
216   };
217 
218  private:
219   static const int kInvalidIndex = -1;
220   int8_t index_;
221 };
222 
223 // A Range from [start, end] of instructions, inclusive of start and end.
224 class Range {
225  public:
Range()226   Range() : start_(kMaxInt), end_(0) {}
Range(int start,int end)227   Range(int start, int end) : start_(start), end_(end) {}
228 
AddInstr(int index)229   void AddInstr(int index) {
230     start_ = std::min(start_, index);
231     end_ = std::max(end_, index);
232   }
233 
AddRange(const Range & other)234   void AddRange(const Range& other) {
235     start_ = std::min(start_, other.start_);
236     end_ = std::max(end_, other.end_);
237   }
238 
239   // Returns true if index is greater than start and less than or equal to end.
Contains(int index)240   bool Contains(int index) { return index >= start_ && index <= end_; }
241 
start() const242   int start() const { return start_; }
end() const243   int end() const { return end_; }
244 
245  private:
246   int start_;
247   int end_;
248 };
249 
250 // Represents a connected region of deferred basic blocks.
251 class DeferredBlocksRegion final {
252  public:
DeferredBlocksRegion(Zone * zone,int number_of_blocks)253   explicit DeferredBlocksRegion(Zone* zone, int number_of_blocks)
254       : spilled_vregs_(zone),
255         blocks_covered_(number_of_blocks, zone),
256         is_frozen_(false) {}
257 
AddBlock(RpoNumber block,MidTierRegisterAllocationData * data)258   void AddBlock(RpoNumber block, MidTierRegisterAllocationData* data) {
259     DCHECK(data->GetBlock(block)->IsDeferred());
260     blocks_covered_.Add(block.ToInt());
261     data->block_state(block).set_deferred_blocks_region(this);
262   }
263 
264   // Trys to adds |vreg| to the list of variables to potentially defer their
265   // output to a spill slot until we enter this deferred block region. Returns
266   // true if successful.
TryDeferSpillOutputUntilEntry(int vreg)267   bool TryDeferSpillOutputUntilEntry(int vreg) {
268     if (spilled_vregs_.count(vreg) != 0) return true;
269     if (is_frozen_) return false;
270     spilled_vregs_.insert(vreg);
271     return true;
272   }
273 
FreezeDeferredSpills()274   void FreezeDeferredSpills() { is_frozen_ = true; }
275 
begin() const276   ZoneSet<int>::const_iterator begin() const { return spilled_vregs_.begin(); }
end() const277   ZoneSet<int>::const_iterator end() const { return spilled_vregs_.end(); }
278 
blocks_covered() const279   const BitVector* blocks_covered() const { return &blocks_covered_; }
280 
281  private:
282   ZoneSet<int> spilled_vregs_;
283   BitVector blocks_covered_;
284   bool is_frozen_;
285 };
286 
287 // VirtualRegisterData stores data specific to a particular virtual register,
288 // and tracks spilled operands for that virtual register.
289 class VirtualRegisterData final {
290  public:
291   VirtualRegisterData() = default;
292 
293   // Define VirtualRegisterData with the type of output that produces this
294   // virtual register.
295   void DefineAsUnallocatedOperand(int virtual_register,
296                                   MachineRepresentation rep, int instr_index,
297                                   bool is_deferred_block,
298                                   bool is_exceptional_call_output);
299   void DefineAsFixedSpillOperand(AllocatedOperand* operand,
300                                  int virtual_register,
301                                  MachineRepresentation rep, int instr_index,
302                                  bool is_deferred_block,
303                                  bool is_exceptional_call_output);
304   void DefineAsConstantOperand(ConstantOperand* operand,
305                                MachineRepresentation rep, int instr_index,
306                                bool is_deferred_block);
307   void DefineAsPhi(int virtual_register, MachineRepresentation rep,
308                    int instr_index, bool is_deferred_block);
309 
310   // Spill an operand that is assigned to this virtual register.
311   void SpillOperand(InstructionOperand* operand, int instr_index,
312                     bool has_constant_policy,
313                     MidTierRegisterAllocationData* data);
314 
315   // Emit gap moves to / from the spill slot.
316   void EmitGapMoveToInputFromSpillSlot(InstructionOperand to_operand,
317                                        int instr_index,
318                                        MidTierRegisterAllocationData* data);
319   void EmitGapMoveFromOutputToSpillSlot(InstructionOperand from_operand,
320                                         const InstructionBlock* current_block,
321                                         int instr_index,
322                                         MidTierRegisterAllocationData* data);
323   void EmitGapMoveToSpillSlot(InstructionOperand from_operand, int instr_index,
324                               MidTierRegisterAllocationData* data);
325 
326   // Adds pending spills for deferred-blocks.
327   void AddDeferredSpillUse(int instr_index,
328                            MidTierRegisterAllocationData* data);
329   void AddDeferredSpillOutput(AllocatedOperand allocated_op, int instr_index,
330                               MidTierRegisterAllocationData* data);
331 
332   // Accessors for spill operand, which may still be pending allocation.
HasSpillOperand() const333   bool HasSpillOperand() const { return spill_operand_ != nullptr; }
spill_operand() const334   InstructionOperand* spill_operand() const {
335     DCHECK(HasSpillOperand());
336     return spill_operand_;
337   }
338 
HasPendingSpillOperand() const339   bool HasPendingSpillOperand() const {
340     return HasSpillOperand() && spill_operand_->IsPending();
341   }
HasAllocatedSpillOperand() const342   bool HasAllocatedSpillOperand() const {
343     return HasSpillOperand() && spill_operand_->IsAllocated();
344   }
HasConstantSpillOperand() const345   bool HasConstantSpillOperand() const {
346     return HasSpillOperand() && spill_operand_->IsConstant();
347   }
348 
349   // Returns true if the virtual register should be spilled when it is output.
NeedsSpillAtOutput() const350   bool NeedsSpillAtOutput() const { return needs_spill_at_output_; }
351 
MarkAsNeedsSpillAtOutput()352   void MarkAsNeedsSpillAtOutput() {
353     if (HasConstantSpillOperand()) return;
354     needs_spill_at_output_ = true;
355     if (HasSpillRange()) spill_range()->ClearDeferredBlockSpills();
356   }
357 
358   // Returns true if the virtual register should be spilled at entry to deferred
359   // blocks in which it is spilled (to avoid spilling on output on
360   // non-deferred blocks).
361   bool NeedsSpillAtDeferredBlocks() const;
362   void EmitDeferredSpillOutputs(MidTierRegisterAllocationData* data);
363 
IsSpilledAt(int instr_index,MidTierRegisterAllocationData * data)364   bool IsSpilledAt(int instr_index, MidTierRegisterAllocationData* data) {
365     DCHECK_GE(instr_index, output_instr_index());
366     if (NeedsSpillAtOutput() || HasConstantSpillOperand()) return true;
367     if (HasSpillOperand() && data->GetBlock(instr_index)->IsDeferred()) {
368       return true;
369     }
370     return false;
371   }
372 
373   // Allocates pending spill operands to the |allocated| spill slot.
374   void AllocatePendingSpillOperand(const AllocatedOperand& allocated);
375 
vreg() const376   int vreg() const { return vreg_; }
rep() const377   MachineRepresentation rep() const { return rep_; }
output_instr_index() const378   int output_instr_index() const { return output_instr_index_; }
is_constant() const379   bool is_constant() const { return is_constant_; }
is_phi() const380   bool is_phi() const { return is_phi_; }
is_defined_in_deferred_block() const381   bool is_defined_in_deferred_block() const {
382     return is_defined_in_deferred_block_;
383   }
is_exceptional_call_output() const384   bool is_exceptional_call_output() const {
385     return is_exceptional_call_output_;
386   }
387 
388   struct DeferredSpillSlotOutput {
389    public:
DeferredSpillSlotOutputv8::internal::compiler::VirtualRegisterData::DeferredSpillSlotOutput390     explicit DeferredSpillSlotOutput(int instr, AllocatedOperand op,
391                                      const BitVector* blocks)
392         : instr_index(instr), operand(op), live_blocks(blocks) {}
393 
394     int instr_index;
395     AllocatedOperand operand;
396     const BitVector* live_blocks;
397   };
398 
399   // Represents the range of instructions for which this virtual register needs
400   // to be spilled on the stack.
401   class SpillRange : public ZoneObject {
402    public:
403     // Defines a spill range for an output operand.
SpillRange(int definition_instr_index,const InstructionBlock * definition_block,MidTierRegisterAllocationData * data)404     SpillRange(int definition_instr_index,
405                const InstructionBlock* definition_block,
406                MidTierRegisterAllocationData* data)
407         : live_range_(definition_instr_index, definition_instr_index),
408           live_blocks_(data->GetBlocksDominatedBy(definition_block)),
409           deferred_spill_outputs_(nullptr) {}
410 
411     // Defines a spill range for a Phi variable.
SpillRange(const InstructionBlock * phi_block,MidTierRegisterAllocationData * data)412     SpillRange(const InstructionBlock* phi_block,
413                MidTierRegisterAllocationData* data)
414         : live_range_(phi_block->first_instruction_index(),
415                       phi_block->first_instruction_index()),
416           live_blocks_(data->GetBlocksDominatedBy(phi_block)),
417           deferred_spill_outputs_(nullptr) {
418       // For phis, add the gap move instructions in the predecssor blocks to
419       // the live range.
420       for (RpoNumber pred_rpo : phi_block->predecessors()) {
421         const InstructionBlock* block = data->GetBlock(pred_rpo);
422         live_range_.AddInstr(block->last_instruction_index());
423       }
424     }
425 
426     SpillRange(const SpillRange&) = delete;
427     SpillRange& operator=(const SpillRange&) = delete;
428 
IsLiveAt(int instr_index,InstructionBlock * block)429     bool IsLiveAt(int instr_index, InstructionBlock* block) {
430       if (!live_range_.Contains(instr_index)) return false;
431 
432       int block_rpo = block->rpo_number().ToInt();
433       if (!live_blocks_->Contains(block_rpo)) return false;
434 
435       if (!HasDeferredBlockSpills()) {
436         return true;
437       } else {
438         // If this spill range is only output for deferred block, then the spill
439         // slot will only be live for the deferred blocks, not all blocks that
440         // the virtual register is live.
441         for (auto deferred_spill_output : *deferred_spill_outputs()) {
442           if (deferred_spill_output.live_blocks->Contains(block_rpo)) {
443             return true;
444           }
445         }
446         return false;
447       }
448     }
449 
ExtendRangeTo(int instr_index)450     void ExtendRangeTo(int instr_index) { live_range_.AddInstr(instr_index); }
451 
AddDeferredSpillOutput(AllocatedOperand allocated_op,int instr_index,MidTierRegisterAllocationData * data)452     void AddDeferredSpillOutput(AllocatedOperand allocated_op, int instr_index,
453                                 MidTierRegisterAllocationData* data) {
454       if (deferred_spill_outputs_ == nullptr) {
455         Zone* zone = data->allocation_zone();
456         deferred_spill_outputs_ =
457             zone->New<ZoneVector<DeferredSpillSlotOutput>>(zone);
458       }
459       const InstructionBlock* block = data->GetBlock(instr_index);
460       DCHECK_EQ(block->first_instruction_index(), instr_index);
461       BlockState& block_state = data->block_state(block->rpo_number());
462       const BitVector* deferred_blocks =
463           block_state.deferred_blocks_region()->blocks_covered();
464       deferred_spill_outputs_->emplace_back(instr_index, allocated_op,
465                                             deferred_blocks);
466     }
467 
ClearDeferredBlockSpills()468     void ClearDeferredBlockSpills() { deferred_spill_outputs_ = nullptr; }
HasDeferredBlockSpills() const469     bool HasDeferredBlockSpills() const {
470       return deferred_spill_outputs_ != nullptr;
471     }
deferred_spill_outputs() const472     const ZoneVector<DeferredSpillSlotOutput>* deferred_spill_outputs() const {
473       DCHECK(HasDeferredBlockSpills());
474       return deferred_spill_outputs_;
475     }
476 
live_range()477     Range& live_range() { return live_range_; }
478 
479    private:
480     Range live_range_;
481     const BitVector* live_blocks_;
482     ZoneVector<DeferredSpillSlotOutput>* deferred_spill_outputs_;
483   };
484 
HasSpillRange() const485   bool HasSpillRange() const { return spill_range_ != nullptr; }
spill_range() const486   SpillRange* spill_range() const {
487     DCHECK(HasSpillRange());
488     return spill_range_;
489   }
490 
491  private:
492   void Initialize(int virtual_register, MachineRepresentation rep,
493                   InstructionOperand* spill_operand, int instr_index,
494                   bool is_phi, bool is_constant,
495                   bool is_defined_in_deferred_block,
496                   bool is_exceptional_call_output);
497 
498   void AddSpillUse(int instr_index, MidTierRegisterAllocationData* data);
499   void AddPendingSpillOperand(PendingOperand* pending_operand);
500   void EnsureSpillRange(MidTierRegisterAllocationData* data);
501   bool TrySpillOnEntryToDeferred(MidTierRegisterAllocationData* data,
502                                  const InstructionBlock* block);
503 
504   InstructionOperand* spill_operand_;
505   SpillRange* spill_range_;
506   int output_instr_index_;
507 
508   int vreg_;
509   MachineRepresentation rep_;
510   bool is_phi_ : 1;
511   bool is_constant_ : 1;
512   bool is_defined_in_deferred_block_ : 1;
513   bool needs_spill_at_output_ : 1;
514   bool is_exceptional_call_output_ : 1;
515 };
516 
VirtualRegisterDataFor(int virtual_register)517 VirtualRegisterData& MidTierRegisterAllocationData::VirtualRegisterDataFor(
518     int virtual_register) {
519   DCHECK_GE(virtual_register, 0);
520   DCHECK_LT(virtual_register, virtual_register_data_.size());
521   return virtual_register_data_[virtual_register];
522 }
523 
Initialize(int virtual_register,MachineRepresentation rep,InstructionOperand * spill_operand,int instr_index,bool is_phi,bool is_constant,bool is_defined_in_deferred_block,bool is_exceptional_call_output)524 void VirtualRegisterData::Initialize(int virtual_register,
525                                      MachineRepresentation rep,
526                                      InstructionOperand* spill_operand,
527                                      int instr_index, bool is_phi,
528                                      bool is_constant,
529                                      bool is_defined_in_deferred_block,
530                                      bool is_exceptional_call_output) {
531   vreg_ = virtual_register;
532   rep_ = rep;
533   spill_operand_ = spill_operand;
534   spill_range_ = nullptr;
535   output_instr_index_ = instr_index;
536   is_phi_ = is_phi;
537   is_constant_ = is_constant;
538   is_defined_in_deferred_block_ = is_defined_in_deferred_block;
539   needs_spill_at_output_ = !is_constant_ && spill_operand_ != nullptr;
540   is_exceptional_call_output_ = is_exceptional_call_output;
541 }
542 
DefineAsConstantOperand(ConstantOperand * operand,MachineRepresentation rep,int instr_index,bool is_deferred_block)543 void VirtualRegisterData::DefineAsConstantOperand(ConstantOperand* operand,
544                                                   MachineRepresentation rep,
545                                                   int instr_index,
546                                                   bool is_deferred_block) {
547   Initialize(operand->virtual_register(), rep, operand, instr_index, false,
548              true, is_deferred_block, false);
549 }
550 
DefineAsFixedSpillOperand(AllocatedOperand * operand,int virtual_register,MachineRepresentation rep,int instr_index,bool is_deferred_block,bool is_exceptional_call_output)551 void VirtualRegisterData::DefineAsFixedSpillOperand(
552     AllocatedOperand* operand, int virtual_register, MachineRepresentation rep,
553     int instr_index, bool is_deferred_block, bool is_exceptional_call_output) {
554   Initialize(virtual_register, rep, operand, instr_index, false, false,
555              is_deferred_block, is_exceptional_call_output);
556 }
557 
DefineAsUnallocatedOperand(int virtual_register,MachineRepresentation rep,int instr_index,bool is_deferred_block,bool is_exceptional_call_output)558 void VirtualRegisterData::DefineAsUnallocatedOperand(
559     int virtual_register, MachineRepresentation rep, int instr_index,
560     bool is_deferred_block, bool is_exceptional_call_output) {
561   Initialize(virtual_register, rep, nullptr, instr_index, false, false,
562              is_deferred_block, is_exceptional_call_output);
563 }
564 
DefineAsPhi(int virtual_register,MachineRepresentation rep,int instr_index,bool is_deferred_block)565 void VirtualRegisterData::DefineAsPhi(int virtual_register,
566                                       MachineRepresentation rep,
567                                       int instr_index, bool is_deferred_block) {
568   Initialize(virtual_register, rep, nullptr, instr_index, true, false,
569              is_deferred_block, false);
570 }
571 
EnsureSpillRange(MidTierRegisterAllocationData * data)572 void VirtualRegisterData::EnsureSpillRange(
573     MidTierRegisterAllocationData* data) {
574   DCHECK(!HasConstantSpillOperand());
575 
576   if (HasSpillRange()) return;
577 
578   const InstructionBlock* definition_block =
579       data->GetBlock(output_instr_index_);
580   if (is_phi()) {
581     // Define a spill slot that is defined for the phi's range.
582     spill_range_ =
583         data->allocation_zone()->New<SpillRange>(definition_block, data);
584   } else {
585     if (is_exceptional_call_output()) {
586       // If this virtual register is output by a call which has an exception
587       // catch handler, then the output will only be live in the IfSuccess
588       // successor block, not the IfException side, so make the definition block
589       // the IfSuccess successor block explicitly.
590       DCHECK_EQ(output_instr_index_,
591                 definition_block->last_instruction_index() - 1);
592       DCHECK_EQ(definition_block->SuccessorCount(), 2);
593       DCHECK(data->GetBlock(definition_block->successors()[1])->IsHandler());
594       definition_block = data->GetBlock(definition_block->successors()[0]);
595     }
596     // The spill slot will be defined after the instruction that outputs it.
597     spill_range_ = data->allocation_zone()->New<SpillRange>(
598         output_instr_index_ + 1, definition_block, data);
599   }
600   data->spilled_virtual_registers().Add(vreg());
601 }
602 
AddSpillUse(int instr_index,MidTierRegisterAllocationData * data)603 void VirtualRegisterData::AddSpillUse(int instr_index,
604                                       MidTierRegisterAllocationData* data) {
605   if (HasConstantSpillOperand()) return;
606 
607   EnsureSpillRange(data);
608   spill_range_->ExtendRangeTo(instr_index);
609 
610   const InstructionBlock* block = data->GetBlock(instr_index);
611   if (!TrySpillOnEntryToDeferred(data, block)) {
612     MarkAsNeedsSpillAtOutput();
613   }
614 }
615 
AddDeferredSpillUse(int instr_index,MidTierRegisterAllocationData * data)616 void VirtualRegisterData::AddDeferredSpillUse(
617     int instr_index, MidTierRegisterAllocationData* data) {
618   DCHECK(data->GetBlock(instr_index)->IsDeferred());
619   DCHECK(!is_defined_in_deferred_block());
620   AddSpillUse(instr_index, data);
621 }
622 
TrySpillOnEntryToDeferred(MidTierRegisterAllocationData * data,const InstructionBlock * block)623 bool VirtualRegisterData::TrySpillOnEntryToDeferred(
624     MidTierRegisterAllocationData* data, const InstructionBlock* block) {
625   BlockState& block_state = data->block_state(block->rpo_number());
626   if (!NeedsSpillAtOutput() && block->IsDeferred() &&
627       !is_defined_in_deferred_block() && !is_constant()) {
628     return block_state.deferred_blocks_region()->TryDeferSpillOutputUntilEntry(
629         vreg());
630   }
631   return false;
632 }
633 
AddDeferredSpillOutput(AllocatedOperand allocated_op,int instr_index,MidTierRegisterAllocationData * data)634 void VirtualRegisterData::AddDeferredSpillOutput(
635     AllocatedOperand allocated_op, int instr_index,
636     MidTierRegisterAllocationData* data) {
637   DCHECK(!NeedsSpillAtOutput());
638   DCHECK(HasSpillRange());
639   spill_range_->AddDeferredSpillOutput(allocated_op, instr_index, data);
640 }
641 
SpillOperand(InstructionOperand * operand,int instr_index,bool has_constant_policy,MidTierRegisterAllocationData * data)642 void VirtualRegisterData::SpillOperand(InstructionOperand* operand,
643                                        int instr_index,
644                                        bool has_constant_policy,
645                                        MidTierRegisterAllocationData* data) {
646   if (!has_constant_policy && HasConstantSpillOperand()) {
647     // Reset the constant spill operand to force a real spill slot since this
648     // operand can't use the constant spill operand.
649     spill_operand_ = nullptr;
650     DCHECK(!HasConstantSpillOperand());
651   }
652   AddSpillUse(instr_index, data);
653   if (HasAllocatedSpillOperand() || HasConstantSpillOperand()) {
654     InstructionOperand::ReplaceWith(operand, spill_operand());
655   } else {
656     PendingOperand pending_op;
657     InstructionOperand::ReplaceWith(operand, &pending_op);
658     AddPendingSpillOperand(PendingOperand::cast(operand));
659   }
660 }
661 
NeedsSpillAtDeferredBlocks() const662 bool VirtualRegisterData::NeedsSpillAtDeferredBlocks() const {
663   return HasSpillRange() && spill_range()->HasDeferredBlockSpills();
664 }
665 
EmitDeferredSpillOutputs(MidTierRegisterAllocationData * data)666 void VirtualRegisterData::EmitDeferredSpillOutputs(
667     MidTierRegisterAllocationData* data) {
668   DCHECK(NeedsSpillAtDeferredBlocks());
669   for (auto deferred_spill : *spill_range()->deferred_spill_outputs()) {
670     EmitGapMoveToSpillSlot(deferred_spill.operand, deferred_spill.instr_index,
671                            data);
672   }
673 }
674 
EmitGapMoveToInputFromSpillSlot(InstructionOperand to_operand,int instr_index,MidTierRegisterAllocationData * data)675 void VirtualRegisterData::EmitGapMoveToInputFromSpillSlot(
676     InstructionOperand to_operand, int instr_index,
677     MidTierRegisterAllocationData* data) {
678   AddSpillUse(instr_index, data);
679   DCHECK(!to_operand.IsPending());
680   if (HasAllocatedSpillOperand() || HasConstantSpillOperand()) {
681     data->AddGapMove(instr_index, Instruction::END, *spill_operand(),
682                      to_operand);
683   } else {
684     MoveOperands* move_ops =
685         data->AddPendingOperandGapMove(instr_index, Instruction::END);
686     AddPendingSpillOperand(PendingOperand::cast(&move_ops->source()));
687     InstructionOperand::ReplaceWith(&move_ops->destination(), &to_operand);
688   }
689 }
690 
EmitGapMoveToSpillSlot(InstructionOperand from_operand,int instr_index,MidTierRegisterAllocationData * data)691 void VirtualRegisterData::EmitGapMoveToSpillSlot(
692     InstructionOperand from_operand, int instr_index,
693     MidTierRegisterAllocationData* data) {
694   AddSpillUse(instr_index, data);
695   if (HasAllocatedSpillOperand() || HasConstantSpillOperand()) {
696     data->AddGapMove(instr_index, Instruction::START, from_operand,
697                      *spill_operand());
698   } else {
699     MoveOperands* move_ops =
700         data->AddPendingOperandGapMove(instr_index, Instruction::START);
701     InstructionOperand::ReplaceWith(&move_ops->source(), &from_operand);
702     AddPendingSpillOperand(PendingOperand::cast(&move_ops->destination()));
703   }
704 }
705 
EmitGapMoveFromOutputToSpillSlot(InstructionOperand from_operand,const InstructionBlock * current_block,int instr_index,MidTierRegisterAllocationData * data)706 void VirtualRegisterData::EmitGapMoveFromOutputToSpillSlot(
707     InstructionOperand from_operand, const InstructionBlock* current_block,
708     int instr_index, MidTierRegisterAllocationData* data) {
709   DCHECK_EQ(data->GetBlock(instr_index), current_block);
710   if (instr_index == current_block->last_instruction_index()) {
711     // Add gap move to the first instruction of every successor block.
712     for (const RpoNumber& succ : current_block->successors()) {
713       const InstructionBlock* successor = data->GetBlock(succ);
714       DCHECK_EQ(1, successor->PredecessorCount());
715       EmitGapMoveToSpillSlot(from_operand, successor->first_instruction_index(),
716                              data);
717     }
718   } else {
719     // Add gap move to the next instruction.
720     EmitGapMoveToSpillSlot(from_operand, instr_index + 1, data);
721   }
722 }
723 
AddPendingSpillOperand(PendingOperand * pending_op)724 void VirtualRegisterData::AddPendingSpillOperand(PendingOperand* pending_op) {
725   DCHECK(HasSpillRange());
726   DCHECK_NULL(pending_op->next());
727   if (HasSpillOperand()) {
728     pending_op->set_next(PendingOperand::cast(spill_operand()));
729   }
730   spill_operand_ = pending_op;
731 }
732 
AllocatePendingSpillOperand(const AllocatedOperand & allocated)733 void VirtualRegisterData::AllocatePendingSpillOperand(
734     const AllocatedOperand& allocated) {
735   DCHECK(!HasAllocatedSpillOperand() && !HasConstantSpillOperand());
736   PendingOperand* current = PendingOperand::cast(spill_operand_);
737   while (current) {
738     PendingOperand* next = current->next();
739     InstructionOperand::ReplaceWith(current, &allocated);
740     current = next;
741   }
742 }
743 
744 // RegisterState represents the state of the |kind| registers at a particular
745 // point in program execution. The RegisterState can be cloned or merged with
746 // other RegisterStates to model branches and merges in program control flow.
747 class RegisterState final : public ZoneObject {
748  public:
New(RegisterKind kind,int num_allocatable_registers,Zone * zone)749   static RegisterState* New(RegisterKind kind, int num_allocatable_registers,
750                             Zone* zone) {
751     return zone->New<RegisterState>(kind, num_allocatable_registers, zone);
752   }
753 
754   RegisterState(RegisterKind kind, int num_allocatable_registers, Zone* zone);
755   RegisterState(const RegisterState& other) V8_NOEXCEPT;
756 
757   bool IsAllocated(RegisterIndex reg);
758   bool IsShared(RegisterIndex reg);
759   int VirtualRegisterForRegister(RegisterIndex reg);
760 
761   // Commit the |reg| with the |allocated| operand.
762   void Commit(RegisterIndex reg, AllocatedOperand allocated,
763               InstructionOperand* operand, MidTierRegisterAllocationData* data);
764 
765   // Spill the contents of |reg| for an instruction in |current_block| using
766   // the |allocated| operand to commit the spill gap move.
767   void Spill(RegisterIndex reg, AllocatedOperand allocated,
768              const InstructionBlock* current_block,
769              MidTierRegisterAllocationData* data);
770 
771   // Add a pending spill of the contents of |reg| at the exit point of a
772   // deferred block at |instr_index| using |allocated| operand to commit the
773   // spill gap move, if the register never gets spilled in a non-deferred block.
774   void SpillForDeferred(RegisterIndex reg, AllocatedOperand allocated,
775                         int instr_index, MidTierRegisterAllocationData* data);
776 
777   // Add a pending gap move from |reg| to |virtual_register|'s spill at the
778   // entry point of a deferred block at |instr_index|, if the |virtual_register|
779   // never spilled in a non-deferred block.
780   void MoveToSpillSlotOnDeferred(RegisterIndex reg, int virtual_register,
781                                  int instr_index,
782                                  MidTierRegisterAllocationData* data);
783 
784   // Allocate |reg| to |virtual_register| for the instruction at |instr_index|.
785   // If the register is later spilled, a gap move will be added immediately
786   // before |instr_index| to move |virtual_register| into this register.
787   void AllocateUse(RegisterIndex reg, int virtual_register,
788                    InstructionOperand* operand, int instr_index,
789                    MidTierRegisterAllocationData* data);
790 
791   // Allocate |reg| as a pending use of |virtual_register| for |operand| in the
792   // instruction at |instr_index|. If |virtual_register| later gets committed to
793   // this register, then |operand| will be too, otherwise |operand| will be
794   // replaced with |virtual_register|'s spill operand.
795   void AllocatePendingUse(RegisterIndex reg, int virtual_register,
796                           InstructionOperand* operand, bool can_be_constant,
797                           int instr_index);
798 
799   // Mark that the register is holding a phi operand that is yet to be allocated
800   // by the source block in the gap just before the last instruction in the
801   // source block.
802   void UseForPhiGapMove(RegisterIndex reg);
803   bool IsPhiGapMove(RegisterIndex reg);
804 
805   // Returns true if |reg| only has pending uses allocated to it.
806   bool HasPendingUsesOnly(RegisterIndex reg);
807 
808   // Clone this RegisterState for a successor block.
809   RegisterState* Clone();
810 
811   // Copy register details for |reg| from |source| to |this| RegisterState.
812   void CopyFrom(RegisterIndex reg, RegisterState* source);
813 
814   // Returns true if the register details for |reg| are equal in |source| and
815   // |this| RegisterStates.
816   bool Equals(RegisterIndex reg, RegisterState* source);
817 
818   // Signals that the registers in this state are going to be shared across
819   // |shared_use_count| blocks.
820   void AddSharedUses(int shared_use_count);
821 
822   // When merging multiple block's RegisterState into the successor block with
823   // |this| RegisterState, commit |reg| as being merged from a given predecessor
824   // block.
825   void CommitAtMerge(RegisterIndex reg);
826 
827   // Resets |reg| if it has register data that was shared with other basic
828   // blocks and was spilled in those blocks.
829   void ResetIfSpilledWhileShared(RegisterIndex reg);
830 
831   // Enable range-based for on allocatable register indices.
begin() const832   RegisterIndex::Iterator begin() const { return RegisterIndex::Iterator(0); }
end() const833   RegisterIndex::Iterator end() const {
834     return RegisterIndex::Iterator(num_allocatable_registers());
835   }
836 
837  private:
838   // Represents a particular register and details of what virtual_register it is
839   // currently holding, and how it should be updated if committed or spilled.
840   class Register final : public ZoneObject {
841    public:
842     Register();
843     void Reset();
844 
845     // Operations for committing, spilling and allocating uses of the register.
846     void Commit(AllocatedOperand allocated_operand,
847                 MidTierRegisterAllocationData* data);
848     void Spill(AllocatedOperand allocated_op,
849                const InstructionBlock* current_block,
850                MidTierRegisterAllocationData* data);
851     void Use(int virtual_register, int instr_index);
852     void PendingUse(InstructionOperand* operand, int virtual_register,
853                     bool can_be_constant, int instr_index);
854     void SpillForDeferred(AllocatedOperand allocated, int instr_index,
855                           MidTierRegisterAllocationData* data);
856     void MoveToSpillSlotOnDeferred(int virtual_register, int instr_index,
857                                    MidTierRegisterAllocationData* data);
858 
859     // Mark register as holding a phi.
860     void MarkAsPhiMove();
is_phi_gap_move() const861     bool is_phi_gap_move() const { return is_phi_gap_move_; }
862 
863     // The register has deferred block spills, that will be emitted if the
864     // register is committed without having been spilled in a non-deferred block
865     void AddDeferredBlockSpill(int instr_index, bool on_exit, Zone* zone);
has_deferred_block_spills() const866     bool has_deferred_block_spills() const {
867       return deferred_block_spills_.has_value();
868     }
869 
870     // Operations related to dealing with a Register that is shared across
871     // multiple basic blocks.
872     void CommitAtMerge();
873     void AddSharedUses(int shared_use_count);
is_shared() const874     bool is_shared() const { return is_shared_; }
was_spilled_while_shared() const875     bool was_spilled_while_shared() const {
876       return is_shared() && !is_allocated();
877     }
878 
is_allocated() const879     bool is_allocated() const {
880       return virtual_register_ != InstructionOperand::kInvalidVirtualRegister;
881     }
882 
883     // The current virtual register held by this register.
virtual_register() const884     int virtual_register() const { return virtual_register_; }
885 
886     // The instruction index for the last use of the current in-progress
887     // allocation of this register in the instruction stream. Used both
888     // as the instruction too add a gap move if |needs_gap_move_on_spill| and
889     // the intruction which the virtual register's spill range should be
890     // extended too if the register is spilled.
last_use_instr_index() const891     int last_use_instr_index() const { return last_use_instr_index_; }
892 
893     // Returns true if a gap move should be added if the register is spilled.
needs_gap_move_on_spill() const894     bool needs_gap_move_on_spill() const { return needs_gap_move_on_spill_; }
895 
896     // Returns a threaded list of the operands that have pending uses of this
897     // register and will be resolved either to the register, or a spill slot
898     // depending on whether this register is spilled or committed.
pending_uses() const899     PendingOperand* pending_uses() const { return pending_uses_; }
900 
901    private:
902     struct DeferredBlockSpill {
DeferredBlockSpillv8::internal::compiler::RegisterState::Register::DeferredBlockSpill903       DeferredBlockSpill(int instr, bool on_exit)
904           : instr_index(instr), on_deferred_exit(on_exit) {}
905 
906       int instr_index;
907       bool on_deferred_exit;
908     };
909 
910     void SpillPendingUses(MidTierRegisterAllocationData* data);
911     void SpillPhiGapMove(AllocatedOperand allocated_op,
912                          const InstructionBlock* block,
913                          MidTierRegisterAllocationData* data);
914 
915     bool needs_gap_move_on_spill_;
916     bool is_shared_;
917     bool is_phi_gap_move_;
918     bool pending_uses_can_use_constant_;
919     int last_use_instr_index_;
920 
921     int num_commits_required_;
922     int virtual_register_;
923     PendingOperand* pending_uses_;
924     base::Optional<ZoneVector<DeferredBlockSpill>> deferred_block_spills_;
925   };
926 
927   void ResetDataFor(RegisterIndex reg);
928 
929   bool HasRegisterData(RegisterIndex reg);
930   void EnsureRegisterData(RegisterIndex reg);
931 
num_allocatable_registers() const932   int num_allocatable_registers() const {
933     return static_cast<int>(register_data_.size());
934   }
935   Register& reg_data(RegisterIndex reg);
zone() const936   Zone* zone() const { return zone_; }
937 
938   ZoneVector<Register*> register_data_;
939   Zone* zone_;
940 };
941 
Register()942 RegisterState::Register::Register() { Reset(); }
943 
Reset()944 void RegisterState::Register::Reset() {
945   is_shared_ = false;
946   is_phi_gap_move_ = false;
947   needs_gap_move_on_spill_ = false;
948   pending_uses_can_use_constant_ = true;
949   last_use_instr_index_ = -1;
950   num_commits_required_ = 0;
951   virtual_register_ = InstructionOperand::kInvalidVirtualRegister;
952   pending_uses_ = nullptr;
953   deferred_block_spills_.reset();
954 }
955 
Use(int virtual_register,int instr_index)956 void RegisterState::Register::Use(int virtual_register, int instr_index) {
957   // A register can have many pending uses, but should only ever have a single
958   // non-pending use, since any subsiquent use will commit the preceeding use
959   // first.
960   DCHECK(!is_allocated());
961   DCHECK(!is_shared());
962   needs_gap_move_on_spill_ = true;
963   virtual_register_ = virtual_register;
964   last_use_instr_index_ = instr_index;
965   num_commits_required_ = 1;
966 }
967 
PendingUse(InstructionOperand * operand,int virtual_register,bool can_be_constant,int instr_index)968 void RegisterState::Register::PendingUse(InstructionOperand* operand,
969                                          int virtual_register,
970                                          bool can_be_constant,
971                                          int instr_index) {
972   DCHECK(!was_spilled_while_shared());
973   if (!is_allocated()) {
974     virtual_register_ = virtual_register;
975     last_use_instr_index_ = instr_index;
976     num_commits_required_ = 1;
977   }
978   DCHECK_EQ(virtual_register_, virtual_register);
979   pending_uses_can_use_constant_ &= can_be_constant;
980 
981   PendingOperand pending_op(pending_uses());
982   InstructionOperand::ReplaceWith(operand, &pending_op);
983   pending_uses_ = PendingOperand::cast(operand);
984 }
985 
MarkAsPhiMove()986 void RegisterState::Register::MarkAsPhiMove() {
987   DCHECK(is_allocated());
988   is_phi_gap_move_ = true;
989 }
990 
AddDeferredBlockSpill(int instr_index,bool on_exit,Zone * zone)991 void RegisterState::Register::AddDeferredBlockSpill(int instr_index,
992                                                     bool on_exit, Zone* zone) {
993   DCHECK(is_allocated());
994   if (!deferred_block_spills_) {
995     deferred_block_spills_.emplace(zone);
996   }
997   deferred_block_spills_->emplace_back(instr_index, on_exit);
998 }
999 
AddSharedUses(int shared_use_count)1000 void RegisterState::Register::AddSharedUses(int shared_use_count) {
1001   DCHECK(!was_spilled_while_shared());
1002   is_shared_ = true;
1003   num_commits_required_ += shared_use_count;
1004 }
1005 
CommitAtMerge()1006 void RegisterState::Register::CommitAtMerge() {
1007   DCHECK(is_shared());
1008   DCHECK(is_allocated());
1009   --num_commits_required_;
1010   // We should still have commits required that will be resolved in the merge
1011   // block.
1012   DCHECK_GT(num_commits_required_, 0);
1013 }
1014 
Commit(AllocatedOperand allocated_op,MidTierRegisterAllocationData * data)1015 void RegisterState::Register::Commit(AllocatedOperand allocated_op,
1016                                      MidTierRegisterAllocationData* data) {
1017   DCHECK(is_allocated());
1018   DCHECK_GT(num_commits_required_, 0);
1019 
1020   if (--num_commits_required_ == 0) {
1021     // Allocate all pending uses to |allocated_op| if this commit is non-shared,
1022     // or if it is the final commit required on a register data shared across
1023     // blocks.
1024     PendingOperand* pending_use = pending_uses();
1025     while (pending_use) {
1026       PendingOperand* next = pending_use->next();
1027       InstructionOperand::ReplaceWith(pending_use, &allocated_op);
1028       pending_use = next;
1029     }
1030     pending_uses_ = nullptr;
1031 
1032     VirtualRegisterData& vreg_data =
1033         data->VirtualRegisterDataFor(virtual_register());
1034 
1035     // If there are deferred block gap moves pending, emit them now that the
1036     // register has been committed.
1037     if (has_deferred_block_spills()) {
1038       for (DeferredBlockSpill& spill : *deferred_block_spills_) {
1039         if (spill.on_deferred_exit) {
1040           vreg_data.EmitGapMoveToInputFromSpillSlot(allocated_op,
1041                                                     spill.instr_index, data);
1042         } else if (!vreg_data.NeedsSpillAtOutput()) {
1043           vreg_data.AddDeferredSpillOutput(allocated_op, spill.instr_index,
1044                                            data);
1045         }
1046       }
1047     }
1048 
1049     // If this register was used as a phi gap move, then it being commited
1050     // is the point at which we have output the Phi.
1051     if (is_phi_gap_move() && vreg_data.NeedsSpillAtDeferredBlocks()) {
1052       vreg_data.EmitDeferredSpillOutputs(data);
1053     }
1054   }
1055   DCHECK_IMPLIES(num_commits_required_ > 0, is_shared());
1056 }
1057 
Spill(AllocatedOperand allocated_op,const InstructionBlock * current_block,MidTierRegisterAllocationData * data)1058 void RegisterState::Register::Spill(AllocatedOperand allocated_op,
1059                                     const InstructionBlock* current_block,
1060                                     MidTierRegisterAllocationData* data) {
1061   VirtualRegisterData& vreg_data =
1062       data->VirtualRegisterDataFor(virtual_register());
1063   SpillPendingUses(data);
1064   if (is_phi_gap_move()) {
1065     SpillPhiGapMove(allocated_op, current_block, data);
1066   }
1067   if (needs_gap_move_on_spill()) {
1068     vreg_data.EmitGapMoveToInputFromSpillSlot(allocated_op,
1069                                               last_use_instr_index(), data);
1070   }
1071   if (has_deferred_block_spills() || !current_block->IsDeferred()) {
1072     vreg_data.MarkAsNeedsSpillAtOutput();
1073   }
1074   // TODO(1180335): Doing a full reset here shouldn't be necessary, but
1075   // investigate if it fixes crbug.com/1180335.
1076   bool is_shared = is_shared_;
1077   Reset();
1078   is_shared_ = is_shared;
1079   DCHECK_IMPLIES(is_shared_, was_spilled_while_shared());
1080 }
1081 
SpillPhiGapMove(AllocatedOperand allocated_op,const InstructionBlock * current_block,MidTierRegisterAllocationData * data)1082 void RegisterState::Register::SpillPhiGapMove(
1083     AllocatedOperand allocated_op, const InstructionBlock* current_block,
1084     MidTierRegisterAllocationData* data) {
1085   DCHECK_EQ(current_block->SuccessorCount(), 1);
1086   const InstructionBlock* phi_block =
1087       data->GetBlock(current_block->successors()[0]);
1088 
1089   // Add gap moves to the spilled phi for all blocks we previously allocated
1090   // assuming the the phi was in a register.
1091   VirtualRegisterData& vreg_data =
1092       data->VirtualRegisterDataFor(virtual_register());
1093   for (RpoNumber predecessor : phi_block->predecessors()) {
1094     // If the predecessor has a lower rpo number than the current block, then
1095     // we have already processed it, so add the required gap move.
1096     if (predecessor > current_block->rpo_number()) {
1097       const InstructionBlock* predecessor_block = data->GetBlock(predecessor);
1098       vreg_data.EmitGapMoveToSpillSlot(
1099           allocated_op, predecessor_block->last_instruction_index(), data);
1100     }
1101   }
1102 }
1103 
SpillPendingUses(MidTierRegisterAllocationData * data)1104 void RegisterState::Register::SpillPendingUses(
1105     MidTierRegisterAllocationData* data) {
1106   VirtualRegisterData& vreg_data =
1107       data->VirtualRegisterDataFor(virtual_register());
1108   PendingOperand* pending_use = pending_uses();
1109   while (pending_use) {
1110     // Spill all the pending operands associated with this register.
1111     PendingOperand* next = pending_use->next();
1112     vreg_data.SpillOperand(pending_use, last_use_instr_index(),
1113                            pending_uses_can_use_constant_, data);
1114     pending_use = next;
1115   }
1116   pending_uses_ = nullptr;
1117 }
1118 
SpillForDeferred(AllocatedOperand allocated,int instr_index,MidTierRegisterAllocationData * data)1119 void RegisterState::Register::SpillForDeferred(
1120     AllocatedOperand allocated, int instr_index,
1121     MidTierRegisterAllocationData* data) {
1122   DCHECK(is_allocated());
1123   DCHECK(is_shared());
1124   // Add a pending deferred spill, then commit the register (with the commit
1125   // being fullfilled by the deferred spill if the register is fully commited).
1126   data->VirtualRegisterDataFor(virtual_register())
1127       .AddDeferredSpillUse(instr_index, data);
1128   AddDeferredBlockSpill(instr_index, true, data->allocation_zone());
1129   Commit(allocated, data);
1130 }
1131 
MoveToSpillSlotOnDeferred(int virtual_register,int instr_index,MidTierRegisterAllocationData * data)1132 void RegisterState::Register::MoveToSpillSlotOnDeferred(
1133     int virtual_register, int instr_index,
1134     MidTierRegisterAllocationData* data) {
1135   DCHECK(!was_spilled_while_shared());
1136   if (!is_allocated()) {
1137     virtual_register_ = virtual_register;
1138     last_use_instr_index_ = instr_index;
1139     num_commits_required_ = 1;
1140   }
1141   AddDeferredBlockSpill(instr_index, false, data->allocation_zone());
1142 }
1143 
RegisterState(RegisterKind kind,int num_allocatable_registers,Zone * zone)1144 RegisterState::RegisterState(RegisterKind kind, int num_allocatable_registers,
1145                              Zone* zone)
1146     : register_data_(num_allocatable_registers, zone), zone_(zone) {}
1147 
RegisterState(const RegisterState & other)1148 RegisterState::RegisterState(const RegisterState& other) V8_NOEXCEPT
1149     : register_data_(other.register_data_.begin(), other.register_data_.end(),
1150                      other.zone_),
1151       zone_(other.zone_) {}
1152 
VirtualRegisterForRegister(RegisterIndex reg)1153 int RegisterState::VirtualRegisterForRegister(RegisterIndex reg) {
1154   if (IsAllocated(reg)) {
1155     return reg_data(reg).virtual_register();
1156   } else {
1157     return InstructionOperand::kInvalidVirtualRegister;
1158   }
1159 }
1160 
IsPhiGapMove(RegisterIndex reg)1161 bool RegisterState::IsPhiGapMove(RegisterIndex reg) {
1162   DCHECK(IsAllocated(reg));
1163   return reg_data(reg).is_phi_gap_move();
1164 }
1165 
Commit(RegisterIndex reg,AllocatedOperand allocated,InstructionOperand * operand,MidTierRegisterAllocationData * data)1166 void RegisterState::Commit(RegisterIndex reg, AllocatedOperand allocated,
1167                            InstructionOperand* operand,
1168                            MidTierRegisterAllocationData* data) {
1169   InstructionOperand::ReplaceWith(operand, &allocated);
1170   if (IsAllocated(reg)) {
1171     reg_data(reg).Commit(allocated, data);
1172     ResetDataFor(reg);
1173   }
1174 }
1175 
Spill(RegisterIndex reg,AllocatedOperand allocated,const InstructionBlock * current_block,MidTierRegisterAllocationData * data)1176 void RegisterState::Spill(RegisterIndex reg, AllocatedOperand allocated,
1177                           const InstructionBlock* current_block,
1178                           MidTierRegisterAllocationData* data) {
1179   DCHECK(IsAllocated(reg));
1180   reg_data(reg).Spill(allocated, current_block, data);
1181   ResetDataFor(reg);
1182 }
1183 
SpillForDeferred(RegisterIndex reg,AllocatedOperand allocated,int instr_index,MidTierRegisterAllocationData * data)1184 void RegisterState::SpillForDeferred(RegisterIndex reg,
1185                                      AllocatedOperand allocated,
1186                                      int instr_index,
1187                                      MidTierRegisterAllocationData* data) {
1188   DCHECK(IsAllocated(reg));
1189   reg_data(reg).SpillForDeferred(allocated, instr_index, data);
1190   ResetDataFor(reg);
1191 }
1192 
MoveToSpillSlotOnDeferred(RegisterIndex reg,int virtual_register,int instr_index,MidTierRegisterAllocationData * data)1193 void RegisterState::MoveToSpillSlotOnDeferred(
1194     RegisterIndex reg, int virtual_register, int instr_index,
1195     MidTierRegisterAllocationData* data) {
1196   EnsureRegisterData(reg);
1197   reg_data(reg).MoveToSpillSlotOnDeferred(virtual_register, instr_index, data);
1198 }
1199 
AllocateUse(RegisterIndex reg,int virtual_register,InstructionOperand * operand,int instr_index,MidTierRegisterAllocationData * data)1200 void RegisterState::AllocateUse(RegisterIndex reg, int virtual_register,
1201                                 InstructionOperand* operand, int instr_index,
1202                                 MidTierRegisterAllocationData* data) {
1203   EnsureRegisterData(reg);
1204   reg_data(reg).Use(virtual_register, instr_index);
1205 }
1206 
AllocatePendingUse(RegisterIndex reg,int virtual_register,InstructionOperand * operand,bool can_be_constant,int instr_index)1207 void RegisterState::AllocatePendingUse(RegisterIndex reg, int virtual_register,
1208                                        InstructionOperand* operand,
1209                                        bool can_be_constant, int instr_index) {
1210   EnsureRegisterData(reg);
1211   reg_data(reg).PendingUse(operand, virtual_register, can_be_constant,
1212                            instr_index);
1213 }
1214 
UseForPhiGapMove(RegisterIndex reg)1215 void RegisterState::UseForPhiGapMove(RegisterIndex reg) {
1216   DCHECK(IsAllocated(reg));
1217   reg_data(reg).MarkAsPhiMove();
1218 }
1219 
reg_data(RegisterIndex reg)1220 RegisterState::Register& RegisterState::reg_data(RegisterIndex reg) {
1221   DCHECK(HasRegisterData(reg));
1222   return *register_data_[reg.ToInt()];
1223 }
1224 
IsShared(RegisterIndex reg)1225 bool RegisterState::IsShared(RegisterIndex reg) {
1226   return HasRegisterData(reg) && reg_data(reg).is_shared();
1227 }
1228 
IsAllocated(RegisterIndex reg)1229 bool RegisterState::IsAllocated(RegisterIndex reg) {
1230   return HasRegisterData(reg) && reg_data(reg).is_allocated();
1231 }
1232 
HasPendingUsesOnly(RegisterIndex reg)1233 bool RegisterState::HasPendingUsesOnly(RegisterIndex reg) {
1234   DCHECK(IsAllocated(reg));
1235   return !reg_data(reg).needs_gap_move_on_spill();
1236 }
1237 
ResetDataFor(RegisterIndex reg)1238 void RegisterState::ResetDataFor(RegisterIndex reg) {
1239   DCHECK(HasRegisterData(reg));
1240   if (reg_data(reg).is_shared()) {
1241     register_data_[reg.ToInt()] = nullptr;
1242   } else {
1243     reg_data(reg).Reset();
1244   }
1245 }
1246 
HasRegisterData(RegisterIndex reg)1247 bool RegisterState::HasRegisterData(RegisterIndex reg) {
1248   DCHECK_LT(reg.ToInt(), register_data_.size());
1249   return register_data_[reg.ToInt()] != nullptr;
1250 }
1251 
EnsureRegisterData(RegisterIndex reg)1252 void RegisterState::EnsureRegisterData(RegisterIndex reg) {
1253   if (!HasRegisterData(reg)) {
1254     register_data_[reg.ToInt()] = zone()->New<RegisterState::Register>();
1255   }
1256 }
1257 
ResetIfSpilledWhileShared(RegisterIndex reg)1258 void RegisterState::ResetIfSpilledWhileShared(RegisterIndex reg) {
1259   if (HasRegisterData(reg) && reg_data(reg).was_spilled_while_shared()) {
1260     ResetDataFor(reg);
1261   }
1262 }
1263 
CommitAtMerge(RegisterIndex reg)1264 void RegisterState::CommitAtMerge(RegisterIndex reg) {
1265   DCHECK(IsAllocated(reg));
1266   reg_data(reg).CommitAtMerge();
1267 }
1268 
CopyFrom(RegisterIndex reg,RegisterState * source)1269 void RegisterState::CopyFrom(RegisterIndex reg, RegisterState* source) {
1270   register_data_[reg.ToInt()] = source->register_data_[reg.ToInt()];
1271 }
1272 
Equals(RegisterIndex reg,RegisterState * other)1273 bool RegisterState::Equals(RegisterIndex reg, RegisterState* other) {
1274   return register_data_[reg.ToInt()] == other->register_data_[reg.ToInt()];
1275 }
1276 
AddSharedUses(int shared_use_count)1277 void RegisterState::AddSharedUses(int shared_use_count) {
1278   for (RegisterIndex reg : *this) {
1279     if (HasRegisterData(reg)) {
1280       reg_data(reg).AddSharedUses(shared_use_count);
1281     }
1282   }
1283 }
1284 
Clone()1285 RegisterState* RegisterState::Clone() {
1286   return zone_->New<RegisterState>(*this);
1287 }
1288 
1289 class RegisterBitVector {
1290  public:
RegisterBitVector()1291   RegisterBitVector() : bits_(0) {}
1292 
operator ==(const RegisterBitVector & other) const1293   bool operator==(const RegisterBitVector& other) const {
1294     return bits_ == other.bits_;
1295   }
1296 
Contains(RegisterIndex reg,MachineRepresentation rep) const1297   bool Contains(RegisterIndex reg, MachineRepresentation rep) const {
1298     return bits_ & reg.ToBit(rep);
1299   }
1300 
GetFirstSet() const1301   RegisterIndex GetFirstSet() const {
1302     return RegisterIndex(base::bits::CountTrailingZeros(bits_));
1303   }
1304 
GetFirstCleared(int max_reg) const1305   RegisterIndex GetFirstCleared(int max_reg) const {
1306     int reg_index = base::bits::CountTrailingZeros(~bits_);
1307     if (reg_index < max_reg) {
1308       return RegisterIndex(reg_index);
1309     } else {
1310       return RegisterIndex::Invalid();
1311     }
1312   }
1313 
Add(RegisterIndex reg,MachineRepresentation rep)1314   void Add(RegisterIndex reg, MachineRepresentation rep) {
1315     bits_ |= reg.ToBit(rep);
1316   }
1317 
Clear(RegisterIndex reg,MachineRepresentation rep)1318   void Clear(RegisterIndex reg, MachineRepresentation rep) {
1319     bits_ &= ~reg.ToBit(rep);
1320   }
1321 
Union(const RegisterBitVector & other)1322   RegisterBitVector Union(const RegisterBitVector& other) {
1323     return RegisterBitVector(bits_ | other.bits_);
1324   }
1325 
Reset()1326   void Reset() { bits_ = 0; }
IsEmpty() const1327   bool IsEmpty() const { return bits_ == 0; }
1328 
1329  private:
1330   friend std::ostream& operator<<(std::ostream&, RegisterBitVector);
RegisterBitVector(uintptr_t bits)1331   explicit RegisterBitVector(uintptr_t bits) : bits_(bits) {}
1332 
1333   static_assert(RegisterConfiguration::kMaxRegisters <= sizeof(uintptr_t) * 8,
1334                 "Maximum registers must fit in uintptr_t bitmap");
1335   uintptr_t bits_;
1336 };
1337 
operator <<(std::ostream & os,RegisterBitVector register_bits)1338 std::ostream& operator<<(std::ostream& os, RegisterBitVector register_bits) {
1339   return os << std::hex << register_bits.bits_ << std::dec;
1340 }
1341 
1342 // A SinglePassRegisterAllocator is a fast register allocator that does a single
1343 // pass through the instruction stream without performing any live-range
1344 // analysis beforehand. It deals with a single RegisterKind, either general or
1345 // double registers, with the MidTierRegisterAllocator choosing the correct
1346 // SinglePassRegisterAllocator based on a values representation.
1347 class SinglePassRegisterAllocator final {
1348  public:
1349   SinglePassRegisterAllocator(RegisterKind kind,
1350                               MidTierRegisterAllocationData* data);
1351 
1352   // Convert to / from a register code and a register index.
1353   RegisterIndex FromRegCode(int reg_code, MachineRepresentation rep) const;
1354   int ToRegCode(RegisterIndex index, MachineRepresentation rep) const;
1355 
1356   // Allocation routines used to allocate a particular operand to either a
1357   // register or a spill slot.
1358   void AllocateConstantOutput(ConstantOperand* operand,
1359                               VirtualRegisterData& vreg, int instr_index);
1360   void AllocateOutput(UnallocatedOperand* operand, VirtualRegisterData& vreg,
1361                       int instr_index);
1362   void AllocateInput(UnallocatedOperand* operand, VirtualRegisterData& vreg,
1363                      int instr_index);
1364   void AllocateSameInputOutput(UnallocatedOperand* output,
1365                                UnallocatedOperand* input,
1366                                VirtualRegisterData& output_vreg,
1367                                VirtualRegisterData& input_vreg,
1368                                int instr_index);
1369   void AllocateGapMoveInput(UnallocatedOperand* operand,
1370                             VirtualRegisterData& vreg, int instr_index);
1371   void AllocateTemp(UnallocatedOperand* operand, int virtual_register,
1372                     MachineRepresentation rep, int instr_index);
1373   void AllocatePhi(VirtualRegisterData& virtual_register,
1374                    const InstructionBlock* block);
1375   void AllocatePhiGapMove(VirtualRegisterData& to_vreg,
1376                           VirtualRegisterData& from_vreg, int instr_index);
1377 
1378   // Reserve any fixed registers for the operands on an instruction before doing
1379   // allocation on the operands.
1380   void ReserveFixedInputRegister(const UnallocatedOperand* operand,
1381                                  int virtual_register,
1382                                  MachineRepresentation rep, int instr_index);
1383   void ReserveFixedTempRegister(const UnallocatedOperand* operand,
1384                                 int virtual_register, MachineRepresentation rep,
1385                                 int instr_index);
1386   void ReserveFixedOutputRegister(const UnallocatedOperand* operand,
1387                                   int virtual_register,
1388                                   MachineRepresentation rep, int instr_index);
1389 
1390   // Spills all registers that are currently holding data, for example, due to
1391   // an instruction that clobbers all registers.
1392   void SpillAllRegisters();
1393 
1394   // Inform the allocator that we are starting / ending a block or ending
1395   // allocation for the current instruction.
1396   void StartBlock(const InstructionBlock* block);
1397   void EndBlock(const InstructionBlock* block);
1398   void EndInstruction();
1399 
1400   void UpdateForDeferredBlock(int instr_index);
1401   void AllocateDeferredBlockSpillOutput(int instr_index,
1402                                         RpoNumber deferred_block,
1403                                         VirtualRegisterData& virtual_register);
1404 
kind() const1405   RegisterKind kind() const { return kind_; }
assigned_registers() const1406   BitVector* assigned_registers() const { return assigned_registers_; }
1407 
1408  private:
1409   enum class UsePosition {
1410     // Operand used at start of instruction.
1411     kStart,
1412     // Operand used at end of instruction.
1413     kEnd,
1414     // Operand is used at both the start and end of instruction.
1415     kAll,
1416     // Operand is not used in the instruction (used when initializing register
1417     // state on block entry).
1418     kNone,
1419   };
1420 
1421   // The allocator is initialized without any RegisterState by default to avoid
1422   // having to allocate per-block allocator state for functions that don't
1423   // allocate registers of a particular type. All allocation functions should
1424   // call EnsureRegisterState to allocate a RegisterState if necessary.
1425   void EnsureRegisterState();
1426 
1427   // Clone the register state from |successor| into the current register state.
1428   void CloneStateFrom(RpoNumber successor);
1429 
1430   // Merge the register state of |successors| into the current register state.
1431   void MergeStateFrom(const InstructionBlock::Successors& successors);
1432 
1433   // Spill a register in a previously processed successor block when merging
1434   // state into the current block.
1435   void SpillRegisterAtMerge(RegisterState* reg_state, RegisterIndex reg,
1436                             MachineRepresentation rep);
1437 
1438   // Introduce a gap move to move |virtual_register| from reg |from| to reg |to|
1439   // on entry to a |successor| block.
1440   void MoveRegisterOnMerge(RegisterIndex from, RegisterIndex to,
1441                            VirtualRegisterData& virtual_register,
1442                            RpoNumber successor, RegisterState* succ_state);
1443 
1444   // Update the virtual register data with the data in register_state_.
1445   void UpdateVirtualRegisterState();
1446 
1447   // Returns true if |virtual_register| is defined after use position |pos| at
1448   // |instr_index|.
1449   bool DefinedAfter(int virtual_register, int instr_index, UsePosition pos);
1450 
1451   // Allocate |reg| to |virtual_register| for |operand| of the instruction at
1452   // |instr_index|. The register will be reserved for this use for the specified
1453   // |pos| use position.
1454   void AllocateUse(RegisterIndex reg, VirtualRegisterData& virtual_register,
1455                    InstructionOperand* operand, int instr_index,
1456                    UsePosition pos);
1457 
1458   // Allocate |reg| to |virtual_register| as a pending use (i.e., only if the
1459   // register is not subsequently spilled) for |operand| of the instruction at
1460   // |instr_index|.
1461   void AllocatePendingUse(RegisterIndex reg,
1462                           VirtualRegisterData& virtual_register,
1463                           InstructionOperand* operand, bool can_be_constant,
1464                           int instr_index);
1465 
1466   // Allocate |operand| to |reg| and add a gap move to move |virtual_register|
1467   // to this register for the instruction at |instr_index|. |reg| will be
1468   // reserved for this use for the specified |pos| use position.
1469   void AllocateUseWithMove(RegisterIndex reg,
1470                            VirtualRegisterData& virtual_register,
1471                            UnallocatedOperand* operand, int instr_index,
1472                            UsePosition pos);
1473 
1474   void CommitRegister(RegisterIndex reg, int virtual_register,
1475                       MachineRepresentation rep, InstructionOperand* operand,
1476                       UsePosition pos);
1477   void SpillRegister(RegisterIndex reg);
1478   void SpillRegisterAndPotentialSimdSibling(RegisterIndex reg,
1479                                             MachineRepresentation rep);
1480   void SpillRegisterForVirtualRegister(int virtual_register);
1481 
1482   // Pre-emptively spill the register at the exit of deferred blocks such that
1483   // uses of this register in non-deferred blocks don't need to be spilled.
1484   void SpillRegisterForDeferred(RegisterIndex reg, int instr_index);
1485 
1486   // Returns an AllocatedOperand corresponding to the use of |reg| for
1487   // |virtual_register|.
1488   AllocatedOperand AllocatedOperandForReg(RegisterIndex reg,
1489                                           MachineRepresentation rep);
1490 
1491   void ReserveFixedRegister(const UnallocatedOperand* operand,
1492                             int virtual_register, MachineRepresentation rep,
1493                             int instr_index, UsePosition pos);
1494   RegisterIndex AllocateOutput(UnallocatedOperand* operand,
1495                                VirtualRegisterData& vreg_data, int instr_index,
1496                                UsePosition pos);
1497   void EmitGapMoveFromOutput(InstructionOperand from, InstructionOperand to,
1498                              int instr_index);
1499 
1500   // Helper functions to choose the best register for a given operand.
1501   V8_INLINE RegisterIndex
1502   ChooseRegisterFor(VirtualRegisterData& virtual_register, int instr_index,
1503                     UsePosition pos, bool must_use_register);
1504   V8_INLINE RegisterIndex ChooseRegisterFor(MachineRepresentation rep,
1505                                             UsePosition pos,
1506                                             bool must_use_register);
1507   V8_INLINE RegisterIndex ChooseFreeRegister(MachineRepresentation rep,
1508                                              UsePosition pos);
1509   V8_INLINE RegisterIndex ChooseFreeRegister(
1510       const RegisterBitVector& allocated_regs, MachineRepresentation rep);
1511   V8_INLINE RegisterIndex ChooseRegisterToSpill(MachineRepresentation rep,
1512                                                 UsePosition pos);
1513 
1514   // Assign, free and mark use's of |reg| for a |virtual_register| at use
1515   // position |pos|.
1516   V8_INLINE void AssignRegister(RegisterIndex reg, int virtual_register,
1517                                 MachineRepresentation rep, UsePosition pos);
1518   V8_INLINE void FreeRegister(RegisterIndex reg, int virtual_register,
1519                               MachineRepresentation rep);
1520   V8_INLINE void MarkRegisterUse(RegisterIndex reg, MachineRepresentation rep,
1521                                  UsePosition pos);
1522   V8_INLINE RegisterBitVector InUseBitmap(UsePosition pos);
1523   V8_INLINE bool IsValidForRep(RegisterIndex reg, MachineRepresentation rep);
1524 
1525   // Return the register allocated to |virtual_register|, if any.
1526   RegisterIndex RegisterForVirtualRegister(int virtual_register);
1527   // Return the virtual register being held by |reg|, or kInvalidVirtualRegister
1528   // if |reg| is unallocated.
1529   int VirtualRegisterForRegister(RegisterIndex reg);
1530 
1531   // Returns true if |reg| is unallocated or holds |virtual_register|.
1532   bool IsFreeOrSameVirtualRegister(RegisterIndex reg, int virtual_register);
1533   // Returns true if |virtual_register| is unallocated or is allocated to |reg|.
1534   bool VirtualRegisterIsUnallocatedOrInReg(int virtual_register,
1535                                            RegisterIndex reg);
1536 
1537   // If {if kFPAliasing kind is COMBINE}, two FP registers alias one SIMD
1538   // register. This returns the index of the higher aliasing FP register from
1539   // the SIMD register index (which is the same as the lower register index).
simdSibling(RegisterIndex reg) const1540   RegisterIndex simdSibling(RegisterIndex reg) const {
1541     CHECK_EQ(kFPAliasing, AliasingKind::kCombine);  // Statically evaluated.
1542     RegisterIndex sibling = RegisterIndex{reg.ToInt() + 1};
1543 #ifdef DEBUG
1544     // Check that {reg} is indeed the lower SIMD half and {sibling} is the
1545     // upper half.
1546     int double_reg_base_code;
1547     DCHECK_EQ(2, data_->config()->GetAliases(
1548                      MachineRepresentation::kSimd128,
1549                      ToRegCode(reg, MachineRepresentation::kSimd128),
1550                      MachineRepresentation::kFloat64, &double_reg_base_code));
1551     DCHECK_EQ(reg, FromRegCode(double_reg_base_code,
1552                                MachineRepresentation::kFloat64));
1553     DCHECK_EQ(sibling, FromRegCode(double_reg_base_code + 1,
1554                                    MachineRepresentation::kFloat64));
1555 #endif  // DEBUG
1556     return sibling;
1557   }
1558 
1559   // Returns a RegisterBitVector representing the allocated registers in
1560   // reg_state.
1561   RegisterBitVector GetAllocatedRegBitVector(RegisterState* reg_state);
1562 
1563   // Check the consistency of reg->vreg and vreg->reg mappings if a debug build.
1564   void CheckConsistency();
1565 
VirtualRegisterDataFor(int virtual_register) const1566   VirtualRegisterData& VirtualRegisterDataFor(int virtual_register) const {
1567     return data_->VirtualRegisterDataFor(virtual_register);
1568   }
1569 
1570   // Virtual register to register mapping.
1571   ZoneVector<RegisterIndex> virtual_register_to_reg_;
1572 
1573   // Current register state during allocation.
1574   RegisterState* register_state_;
1575 
1576   // The current block being processed.
1577   const InstructionBlock* current_block_;
1578 
1579   const RegisterKind kind_;
1580   const int num_allocatable_registers_;
1581   ZoneVector<RegisterIndex> reg_code_to_index_;
1582   const int* index_to_reg_code_;
1583   BitVector* assigned_registers_;
1584 
1585   MidTierRegisterAllocationData* data_;
1586 
1587   RegisterBitVector in_use_at_instr_start_bits_;
1588   RegisterBitVector in_use_at_instr_end_bits_;
1589   RegisterBitVector allocated_registers_bits_;
1590   RegisterBitVector same_input_output_registers_bits_;
1591 
1592   // These fields are only used when kFPAliasing == COMBINE.
1593   base::Optional<ZoneVector<RegisterIndex>> float32_reg_code_to_index_;
1594   base::Optional<ZoneVector<int>> index_to_float32_reg_code_;
1595   base::Optional<ZoneVector<RegisterIndex>> simd128_reg_code_to_index_;
1596   base::Optional<ZoneVector<int>> index_to_simd128_reg_code_;
1597 };
1598 
SinglePassRegisterAllocator(RegisterKind kind,MidTierRegisterAllocationData * data)1599 SinglePassRegisterAllocator::SinglePassRegisterAllocator(
1600     RegisterKind kind, MidTierRegisterAllocationData* data)
1601     : virtual_register_to_reg_(data->code()->VirtualRegisterCount(),
1602                                data->allocation_zone()),
1603       register_state_(nullptr),
1604       current_block_(nullptr),
1605       kind_(kind),
1606       num_allocatable_registers_(
1607           GetAllocatableRegisterCount(data->config(), kind)),
1608       reg_code_to_index_(GetRegisterCount(data->config(), kind),
1609                          data->allocation_zone()),
1610       index_to_reg_code_(GetAllocatableRegisterCodes(data->config(), kind)),
1611       assigned_registers_(data->code_zone()->New<BitVector>(
1612           GetRegisterCount(data->config(), kind), data->code_zone())),
1613       data_(data),
1614       in_use_at_instr_start_bits_(),
1615       in_use_at_instr_end_bits_(),
1616       allocated_registers_bits_(),
1617       same_input_output_registers_bits_() {
1618   for (int i = 0; i < num_allocatable_registers_; i++) {
1619     int reg_code = index_to_reg_code_[i];
1620     reg_code_to_index_[reg_code] = RegisterIndex(i);
1621   }
1622 
1623   // If the architecture has COMBINE FP aliasing, initialize float and
1624   // simd128 specific register details.
1625   if (kFPAliasing == AliasingKind::kCombine && kind == RegisterKind::kDouble) {
1626     const RegisterConfiguration* config = data->config();
1627 
1628     //  Float registers.
1629     float32_reg_code_to_index_.emplace(config->num_float_registers(),
1630                                        data->allocation_zone());
1631     index_to_float32_reg_code_.emplace(num_allocatable_registers_, -1,
1632                                        data->allocation_zone());
1633     for (int i = 0; i < config->num_allocatable_float_registers(); i++) {
1634       int reg_code = config->allocatable_float_codes()[i];
1635       // Only add even float register codes to avoid overlapping multiple float
1636       // registers on each RegisterIndex.
1637       if (reg_code % 2 != 0) continue;
1638       int double_reg_base_code;
1639       CHECK_EQ(1, config->GetAliases(MachineRepresentation::kFloat32, reg_code,
1640                                      MachineRepresentation::kFloat64,
1641                                      &double_reg_base_code));
1642       RegisterIndex double_reg(reg_code_to_index_[double_reg_base_code]);
1643       float32_reg_code_to_index_->at(reg_code) = double_reg;
1644       index_to_float32_reg_code_->at(double_reg.ToInt()) = reg_code;
1645     }
1646 
1647     //  Simd128 registers.
1648     simd128_reg_code_to_index_.emplace(config->num_simd128_registers(),
1649                                        data->allocation_zone());
1650     index_to_simd128_reg_code_.emplace(num_allocatable_registers_, -1,
1651                                        data->allocation_zone());
1652     for (int i = 0; i < config->num_allocatable_simd128_registers(); i++) {
1653       int reg_code = config->allocatable_simd128_codes()[i];
1654       int double_reg_base_code;
1655       CHECK_EQ(2, config->GetAliases(MachineRepresentation::kSimd128, reg_code,
1656                                      MachineRepresentation::kFloat64,
1657                                      &double_reg_base_code));
1658       RegisterIndex double_reg{reg_code_to_index_[double_reg_base_code]};
1659       // We later rely on the fact that the two aliasing double registers are at
1660       // consecutive indexes.
1661       DCHECK_EQ(double_reg.ToInt() + 1,
1662                 reg_code_to_index_[double_reg_base_code + 1].ToInt());
1663       simd128_reg_code_to_index_->at(reg_code) = double_reg;
1664       index_to_simd128_reg_code_->at(double_reg.ToInt()) = reg_code;
1665     }
1666   }
1667 }
1668 
VirtualRegisterForRegister(RegisterIndex reg)1669 int SinglePassRegisterAllocator::VirtualRegisterForRegister(RegisterIndex reg) {
1670   return register_state_->VirtualRegisterForRegister(reg);
1671 }
1672 
RegisterForVirtualRegister(int virtual_register)1673 RegisterIndex SinglePassRegisterAllocator::RegisterForVirtualRegister(
1674     int virtual_register) {
1675   DCHECK_NE(virtual_register, InstructionOperand::kInvalidVirtualRegister);
1676   return virtual_register_to_reg_[virtual_register];
1677 }
1678 
UpdateForDeferredBlock(int instr_index)1679 void SinglePassRegisterAllocator::UpdateForDeferredBlock(int instr_index) {
1680   if (!register_state_) return;
1681   for (RegisterIndex reg : *register_state_) {
1682     SpillRegisterForDeferred(reg, instr_index);
1683   }
1684 }
1685 
EndInstruction()1686 void SinglePassRegisterAllocator::EndInstruction() {
1687   in_use_at_instr_end_bits_.Reset();
1688   in_use_at_instr_start_bits_.Reset();
1689   same_input_output_registers_bits_.Reset();
1690 }
1691 
StartBlock(const InstructionBlock * block)1692 void SinglePassRegisterAllocator::StartBlock(const InstructionBlock* block) {
1693   DCHECK_NULL(register_state_);
1694   DCHECK_NULL(current_block_);
1695   DCHECK(in_use_at_instr_start_bits_.IsEmpty());
1696   DCHECK(in_use_at_instr_end_bits_.IsEmpty());
1697   DCHECK(allocated_registers_bits_.IsEmpty());
1698   DCHECK(same_input_output_registers_bits_.IsEmpty());
1699 
1700   // Update the current block we are processing.
1701   current_block_ = block;
1702 
1703   if (block->SuccessorCount() == 1) {
1704     // If we have only a single successor, we can directly clone our state
1705     // from that successor.
1706     CloneStateFrom(block->successors()[0]);
1707   } else if (block->SuccessorCount() > 1) {
1708     // If we have multiple successors, merge the state from all the successors
1709     // into our block.
1710     MergeStateFrom(block->successors());
1711   }
1712 }
1713 
EndBlock(const InstructionBlock * block)1714 void SinglePassRegisterAllocator::EndBlock(const InstructionBlock* block) {
1715   DCHECK(in_use_at_instr_start_bits_.IsEmpty());
1716   DCHECK(in_use_at_instr_end_bits_.IsEmpty());
1717   DCHECK(same_input_output_registers_bits_.IsEmpty());
1718 
1719   // If we didn't allocate any registers of this kind, or we have reached the
1720   // start, nothing to do here.
1721   if (!register_state_ || block->PredecessorCount() == 0) {
1722     current_block_ = nullptr;
1723     return;
1724   }
1725 
1726   if (block->PredecessorCount() > 1) {
1727     register_state_->AddSharedUses(static_cast<int>(block->PredecessorCount()) -
1728                                    1);
1729   }
1730 
1731   BlockState& block_state = data_->block_state(block->rpo_number());
1732   block_state.set_register_in_state(register_state_, kind());
1733 
1734   // Remove virtual register to register mappings and clear register state.
1735   // We will update the register state when starting the next block.
1736   while (!allocated_registers_bits_.IsEmpty()) {
1737     RegisterIndex reg = allocated_registers_bits_.GetFirstSet();
1738     VirtualRegisterData& vreg_data =
1739         data_->VirtualRegisterDataFor(VirtualRegisterForRegister(reg));
1740     FreeRegister(reg, vreg_data.vreg(), vreg_data.rep());
1741   }
1742   current_block_ = nullptr;
1743   register_state_ = nullptr;
1744 }
1745 
CloneStateFrom(RpoNumber successor)1746 void SinglePassRegisterAllocator::CloneStateFrom(RpoNumber successor) {
1747   BlockState& block_state = data_->block_state(successor);
1748   RegisterState* successor_registers = block_state.register_in_state(kind());
1749   if (successor_registers != nullptr) {
1750     if (data_->GetBlock(successor)->PredecessorCount() == 1) {
1751       // Avoids cloning for successors where we are the only predecessor.
1752       register_state_ = successor_registers;
1753     } else {
1754       register_state_ = successor_registers->Clone();
1755     }
1756     UpdateVirtualRegisterState();
1757   }
1758 }
1759 
MergeStateFrom(const InstructionBlock::Successors & successors)1760 void SinglePassRegisterAllocator::MergeStateFrom(
1761     const InstructionBlock::Successors& successors) {
1762   for (RpoNumber successor : successors) {
1763     BlockState& block_state = data_->block_state(successor);
1764     RegisterState* successor_registers = block_state.register_in_state(kind());
1765     if (successor_registers == nullptr) {
1766       continue;
1767     }
1768 
1769     if (register_state_ == nullptr) {
1770       // If we haven't merged any register state yet, just use successor's
1771       // register directly.
1772       register_state_ = successor_registers;
1773       UpdateVirtualRegisterState();
1774     } else {
1775       // Otherwise try to merge our state with the existing state.
1776       RegisterBitVector processed_regs;
1777       RegisterBitVector succ_allocated_regs =
1778           GetAllocatedRegBitVector(successor_registers);
1779       for (RegisterIndex reg : *successor_registers) {
1780         // If |reg| isn't allocated in successor registers, nothing to do.
1781         if (!successor_registers->IsAllocated(reg)) continue;
1782 
1783         int virtual_register =
1784             successor_registers->VirtualRegisterForRegister(reg);
1785         VirtualRegisterData& vreg_data =
1786             VirtualRegisterDataFor(virtual_register);
1787         MachineRepresentation rep = vreg_data.rep();
1788 
1789         // If we have already processed |reg|, e.g., adding gap move to that
1790         // register, then we can continue.
1791         if (processed_regs.Contains(reg, rep)) continue;
1792         processed_regs.Add(reg, rep);
1793 
1794         bool reg_in_use = register_state_->IsAllocated(reg);
1795         // For COMBINE FP aliasing, the register is also "in use" if the
1796         // FP register for the upper half is allocated.
1797         if (kFPAliasing == AliasingKind::kCombine &&
1798             rep == MachineRepresentation::kSimd128) {
1799           reg_in_use |= register_state_->IsAllocated(simdSibling(reg));
1800         }
1801         // Similarly (but the other way around), the register might be the upper
1802         // half of a SIMD register that is allocated.
1803         if (kFPAliasing == AliasingKind::kCombine &&
1804             (rep == MachineRepresentation::kFloat64 ||
1805              rep == MachineRepresentation::kFloat32)) {
1806           int simd_reg_code;
1807           CHECK_EQ(1, data_->config()->GetAliases(
1808                           rep, ToRegCode(reg, rep),
1809                           MachineRepresentation::kSimd128, &simd_reg_code));
1810           // Sanity check: The SIMD reg code should be the shifted FP reg code.
1811           DCHECK_EQ(simd_reg_code,
1812                     ToRegCode(reg, rep) >>
1813                         (rep == MachineRepresentation::kFloat64 ? 1 : 2));
1814           RegisterIndex simd_reg =
1815               FromRegCode(simd_reg_code, MachineRepresentation::kSimd128);
1816           reg_in_use |=
1817               simd_reg.is_valid() && register_state_->IsAllocated(simd_reg) &&
1818               VirtualRegisterDataFor(VirtualRegisterForRegister(simd_reg))
1819                       .rep() == MachineRepresentation::kSimd128;
1820         }
1821 
1822         if (!reg_in_use) {
1823           DCHECK(successor_registers->IsAllocated(reg));
1824           if (RegisterForVirtualRegister(virtual_register).is_valid()) {
1825             // If we already hold the virtual register in a different register
1826             // then spill this register in the sucessor block to avoid
1827             // invalidating the 1:1 vreg<->reg mapping.
1828             // TODO(rmcilroy): Add a gap move to avoid spilling.
1829             SpillRegisterAtMerge(successor_registers, reg, rep);
1830             continue;
1831           }
1832           // Register is free in our current register state, so merge the
1833           // successor block's register details into it.
1834           register_state_->CopyFrom(reg, successor_registers);
1835           AssignRegister(reg, virtual_register, rep, UsePosition::kNone);
1836           continue;
1837         }
1838 
1839         // Register is in use in the current register state.
1840         if (successor_registers->Equals(reg, register_state_)) {
1841           // Both match, keep the merged register data.
1842           register_state_->CommitAtMerge(reg);
1843           continue;
1844         }
1845         // Try to find a new register for this successor register in the
1846         // merge block, and add a gap move on entry of the successor block.
1847         RegisterIndex new_reg = RegisterForVirtualRegister(virtual_register);
1848         if (!new_reg.is_valid()) {
1849           new_reg = ChooseFreeRegister(
1850               allocated_registers_bits_.Union(succ_allocated_regs), rep);
1851         } else if (new_reg != reg) {
1852           // Spill the |new_reg| in the successor block to be able to use it
1853           // for this gap move. It would be spilled anyway since it contains
1854           // a different virtual register than the merge block.
1855           SpillRegisterAtMerge(successor_registers, new_reg, rep);
1856         }
1857 
1858         if (new_reg.is_valid()) {
1859           MoveRegisterOnMerge(new_reg, reg, vreg_data, successor,
1860                               successor_registers);
1861           processed_regs.Add(new_reg, rep);
1862         } else {
1863           SpillRegisterAtMerge(successor_registers, reg, rep);
1864         }
1865       }
1866     }
1867   }
1868 }
1869 
GetAllocatedRegBitVector(RegisterState * reg_state)1870 RegisterBitVector SinglePassRegisterAllocator::GetAllocatedRegBitVector(
1871     RegisterState* reg_state) {
1872   RegisterBitVector allocated_regs;
1873   for (RegisterIndex reg : *reg_state) {
1874     if (reg_state->IsAllocated(reg)) {
1875       VirtualRegisterData virtual_register =
1876           VirtualRegisterDataFor(reg_state->VirtualRegisterForRegister(reg));
1877       allocated_regs.Add(reg, virtual_register.rep());
1878     }
1879   }
1880   return allocated_regs;
1881 }
1882 
SpillRegisterAtMerge(RegisterState * reg_state,RegisterIndex reg,MachineRepresentation rep)1883 void SinglePassRegisterAllocator::SpillRegisterAtMerge(
1884     RegisterState* reg_state, RegisterIndex reg, MachineRepresentation rep) {
1885   DCHECK_NE(reg_state, register_state_);
1886   if (reg_state->IsAllocated(reg)) {
1887     int virtual_register = reg_state->VirtualRegisterForRegister(reg);
1888     VirtualRegisterData& vreg_data =
1889         data_->VirtualRegisterDataFor(virtual_register);
1890     AllocatedOperand allocated = AllocatedOperandForReg(reg, vreg_data.rep());
1891     reg_state->Spill(reg, allocated, current_block_, data_);
1892   }
1893   // Also spill the "simd sibling" register if we want to use {reg} for SIMD.
1894   if (kFPAliasing == AliasingKind::kCombine &&
1895       rep == MachineRepresentation::kSimd128) {
1896     RegisterIndex sibling = simdSibling(reg);
1897     if (reg_state->IsAllocated(sibling)) {
1898       int virtual_register = reg_state->VirtualRegisterForRegister(sibling);
1899       VirtualRegisterData& vreg_data =
1900           data_->VirtualRegisterDataFor(virtual_register);
1901       AllocatedOperand allocated =
1902           AllocatedOperandForReg(sibling, vreg_data.rep());
1903       reg_state->Spill(sibling, allocated, current_block_, data_);
1904     }
1905   }
1906   // Similarly, spill the whole SIMD register if we want to use a part of it.
1907   if (kFPAliasing == AliasingKind::kCombine &&
1908       (rep == MachineRepresentation::kFloat64 ||
1909        rep == MachineRepresentation::kFloat32)) {
1910     int simd_reg_code;
1911     CHECK_EQ(1, data_->config()->GetAliases(rep, ToRegCode(reg, rep),
1912                                             MachineRepresentation::kSimd128,
1913                                             &simd_reg_code));
1914     // Sanity check: The SIMD register code should be the shifted {reg_code}.
1915     DCHECK_EQ(simd_reg_code,
1916               ToRegCode(reg, rep) >>
1917                   (rep == MachineRepresentation::kFloat64 ? 1 : 2));
1918     RegisterIndex simd_reg =
1919         FromRegCode(simd_reg_code, MachineRepresentation::kSimd128);
1920     DCHECK(!simd_reg.is_valid() || simd_reg == reg ||
1921            simdSibling(simd_reg) == reg);
1922     if (simd_reg.is_valid() && reg_state->IsAllocated(simd_reg)) {
1923       int virtual_register = reg_state->VirtualRegisterForRegister(simd_reg);
1924       VirtualRegisterData& vreg_data =
1925           data_->VirtualRegisterDataFor(virtual_register);
1926       if (vreg_data.rep() == MachineRepresentation::kSimd128) {
1927         AllocatedOperand allocated =
1928             AllocatedOperandForReg(simd_reg, vreg_data.rep());
1929         reg_state->Spill(simd_reg, allocated, current_block_, data_);
1930       }
1931     }
1932   }
1933 }
1934 
MoveRegisterOnMerge(RegisterIndex from,RegisterIndex to,VirtualRegisterData & virtual_register,RpoNumber successor,RegisterState * succ_state)1935 void SinglePassRegisterAllocator::MoveRegisterOnMerge(
1936     RegisterIndex from, RegisterIndex to, VirtualRegisterData& virtual_register,
1937     RpoNumber successor, RegisterState* succ_state) {
1938   int instr_index = data_->GetBlock(successor)->first_instruction_index();
1939   MoveOperands* move =
1940       data_->AddPendingOperandGapMove(instr_index, Instruction::START);
1941   succ_state->Commit(to, AllocatedOperandForReg(to, virtual_register.rep()),
1942                      &move->destination(), data_);
1943   AllocatePendingUse(from, virtual_register, &move->source(), true,
1944                      instr_index);
1945 }
1946 
UpdateVirtualRegisterState()1947 void SinglePassRegisterAllocator::UpdateVirtualRegisterState() {
1948   // Update to the new register state and update vreg_to_register map and
1949   // resetting any shared registers that were spilled by another block.
1950   DCHECK_NOT_NULL(register_state_);
1951   for (RegisterIndex reg : *register_state_) {
1952     register_state_->ResetIfSpilledWhileShared(reg);
1953     int virtual_register = VirtualRegisterForRegister(reg);
1954     if (virtual_register != InstructionOperand::kInvalidVirtualRegister) {
1955       MachineRepresentation rep =
1956           data_->VirtualRegisterDataFor(virtual_register).rep();
1957       AssignRegister(reg, virtual_register, rep, UsePosition::kNone);
1958     }
1959   }
1960   CheckConsistency();
1961 }
1962 
CheckConsistency()1963 void SinglePassRegisterAllocator::CheckConsistency() {
1964 #ifdef DEBUG
1965   int virtual_register = -1;
1966   for (RegisterIndex reg : virtual_register_to_reg_) {
1967     ++virtual_register;
1968     if (!reg.is_valid()) continue;
1969     DCHECK_NOT_NULL(register_state_);
1970     // The register must be set to allocated.
1971     DCHECK(register_state_->IsAllocated(reg));
1972     // reg <-> vreg linking is consistent.
1973     DCHECK_EQ(virtual_register, VirtualRegisterForRegister(reg));
1974   }
1975   DCHECK_EQ(data_->code()->VirtualRegisterCount() - 1, virtual_register);
1976 
1977   RegisterBitVector used_registers;
1978   for (RegisterIndex reg : *register_state_) {
1979     if (!register_state_->IsAllocated(reg)) continue;
1980     int virtual_register = VirtualRegisterForRegister(reg);
1981     // reg <-> vreg linking is consistent.
1982     DCHECK_EQ(reg, RegisterForVirtualRegister(virtual_register));
1983     MachineRepresentation rep = VirtualRegisterDataFor(virtual_register).rep();
1984     // Allocated registers do not overlap.
1985     DCHECK(!used_registers.Contains(reg, rep));
1986     used_registers.Add(reg, rep);
1987   }
1988   // The {allocated_registers_bits_} bitvector is accurate.
1989   DCHECK_EQ(used_registers, allocated_registers_bits_);
1990 #endif
1991 }
1992 
FromRegCode(int reg_code,MachineRepresentation rep) const1993 RegisterIndex SinglePassRegisterAllocator::FromRegCode(
1994     int reg_code, MachineRepresentation rep) const {
1995   if (kFPAliasing == AliasingKind::kCombine &&
1996       kind() == RegisterKind::kDouble) {
1997     if (rep == MachineRepresentation::kFloat32) {
1998       return RegisterIndex(float32_reg_code_to_index_->at(reg_code));
1999     } else if (rep == MachineRepresentation::kSimd128) {
2000       return RegisterIndex(simd128_reg_code_to_index_->at(reg_code));
2001     }
2002     DCHECK_EQ(rep, MachineRepresentation::kFloat64);
2003   }
2004 
2005   return RegisterIndex(reg_code_to_index_[reg_code]);
2006 }
2007 
ToRegCode(RegisterIndex reg,MachineRepresentation rep) const2008 int SinglePassRegisterAllocator::ToRegCode(RegisterIndex reg,
2009                                            MachineRepresentation rep) const {
2010   if (kFPAliasing == AliasingKind::kCombine &&
2011       kind() == RegisterKind::kDouble) {
2012     if (rep == MachineRepresentation::kFloat32) {
2013       DCHECK_NE(-1, index_to_float32_reg_code_->at(reg.ToInt()));
2014       return index_to_float32_reg_code_->at(reg.ToInt());
2015     } else if (rep == MachineRepresentation::kSimd128) {
2016       DCHECK_NE(-1, index_to_simd128_reg_code_->at(reg.ToInt()));
2017       return index_to_simd128_reg_code_->at(reg.ToInt());
2018     }
2019     DCHECK_EQ(rep, MachineRepresentation::kFloat64);
2020   }
2021   return index_to_reg_code_[reg.ToInt()];
2022 }
2023 
VirtualRegisterIsUnallocatedOrInReg(int virtual_register,RegisterIndex reg)2024 bool SinglePassRegisterAllocator::VirtualRegisterIsUnallocatedOrInReg(
2025     int virtual_register, RegisterIndex reg) {
2026   RegisterIndex existing_reg = RegisterForVirtualRegister(virtual_register);
2027   return !existing_reg.is_valid() || existing_reg == reg;
2028 }
2029 
IsFreeOrSameVirtualRegister(RegisterIndex reg,int virtual_register)2030 bool SinglePassRegisterAllocator::IsFreeOrSameVirtualRegister(
2031     RegisterIndex reg, int virtual_register) {
2032   int allocated_vreg = VirtualRegisterForRegister(reg);
2033   return allocated_vreg == InstructionOperand::kInvalidVirtualRegister ||
2034          allocated_vreg == virtual_register;
2035 }
2036 
EmitGapMoveFromOutput(InstructionOperand from,InstructionOperand to,int instr_index)2037 void SinglePassRegisterAllocator::EmitGapMoveFromOutput(InstructionOperand from,
2038                                                         InstructionOperand to,
2039                                                         int instr_index) {
2040   DCHECK(from.IsAllocated());
2041   DCHECK(to.IsAllocated());
2042   const InstructionBlock* block = current_block_;
2043   DCHECK_EQ(data_->GetBlock(instr_index), block);
2044   if (instr_index == block->last_instruction_index()) {
2045     // Add gap move to the first instruction of every successor block.
2046     for (const RpoNumber& succ : block->successors()) {
2047       const InstructionBlock* successor = data_->GetBlock(succ);
2048       DCHECK_EQ(1, successor->PredecessorCount());
2049       data_->AddGapMove(successor->first_instruction_index(),
2050                         Instruction::START, from, to);
2051     }
2052   } else {
2053     data_->AddGapMove(instr_index + 1, Instruction::START, from, to);
2054   }
2055 }
2056 
AssignRegister(RegisterIndex reg,int virtual_register,MachineRepresentation rep,UsePosition pos)2057 void SinglePassRegisterAllocator::AssignRegister(RegisterIndex reg,
2058                                                  int virtual_register,
2059                                                  MachineRepresentation rep,
2060                                                  UsePosition pos) {
2061   assigned_registers()->Add(ToRegCode(reg, rep));
2062   allocated_registers_bits_.Add(reg, rep);
2063   MarkRegisterUse(reg, rep, pos);
2064   if (virtual_register != InstructionOperand::kInvalidVirtualRegister) {
2065     virtual_register_to_reg_[virtual_register] = reg;
2066   }
2067 }
2068 
MarkRegisterUse(RegisterIndex reg,MachineRepresentation rep,UsePosition pos)2069 void SinglePassRegisterAllocator::MarkRegisterUse(RegisterIndex reg,
2070                                                   MachineRepresentation rep,
2071                                                   UsePosition pos) {
2072   if (pos == UsePosition::kStart || pos == UsePosition::kAll) {
2073     in_use_at_instr_start_bits_.Add(reg, rep);
2074   }
2075   if (pos == UsePosition::kEnd || pos == UsePosition::kAll) {
2076     in_use_at_instr_end_bits_.Add(reg, rep);
2077   }
2078 }
2079 
FreeRegister(RegisterIndex reg,int virtual_register,MachineRepresentation rep)2080 void SinglePassRegisterAllocator::FreeRegister(RegisterIndex reg,
2081                                                int virtual_register,
2082                                                MachineRepresentation rep) {
2083   allocated_registers_bits_.Clear(reg, rep);
2084   if (virtual_register != InstructionOperand::kInvalidVirtualRegister) {
2085     virtual_register_to_reg_[virtual_register] = RegisterIndex::Invalid();
2086   }
2087 }
2088 
ChooseRegisterFor(VirtualRegisterData & virtual_register,int instr_index,UsePosition pos,bool must_use_register)2089 RegisterIndex SinglePassRegisterAllocator::ChooseRegisterFor(
2090     VirtualRegisterData& virtual_register, int instr_index, UsePosition pos,
2091     bool must_use_register) {
2092   DCHECK_NE(pos, UsePosition::kNone);
2093   MachineRepresentation rep = virtual_register.rep();
2094 
2095   // If register is already allocated to the virtual register, use that.
2096   RegisterIndex reg = RegisterForVirtualRegister(virtual_register.vreg());
2097 
2098   // If we don't need a register, only try to allocate one if the virtual
2099   // register hasn't yet been spilled, to try to avoid spilling it.
2100   if (!reg.is_valid() && (must_use_register ||
2101                           !virtual_register.IsSpilledAt(instr_index, data_))) {
2102     reg = ChooseRegisterFor(rep, pos, must_use_register);
2103   } else if (reg.is_valid() &&
2104              same_input_output_registers_bits_.Contains(reg, rep) &&
2105              pos != UsePosition::kStart) {
2106     // If we are trying to allocate a register that was used as a
2107     // same_input_output operand, then we can't use it for an input that expands
2108     // past UsePosition::kStart.
2109     if (must_use_register) {
2110       // Use a new register instead.
2111       reg = ChooseRegisterFor(rep, pos, must_use_register);
2112     } else {
2113       // Use a spill slot.
2114       reg = RegisterIndex::Invalid();
2115     }
2116   }
2117   return reg;
2118 }
2119 
ChooseRegisterFor(MachineRepresentation rep,UsePosition pos,bool must_use_register)2120 RegisterIndex SinglePassRegisterAllocator::ChooseRegisterFor(
2121     MachineRepresentation rep, UsePosition pos, bool must_use_register) {
2122   DCHECK_NE(pos, UsePosition::kNone);
2123   RegisterIndex reg = ChooseFreeRegister(rep, pos);
2124   if (!reg.is_valid() && must_use_register) {
2125     reg = ChooseRegisterToSpill(rep, pos);
2126     SpillRegisterAndPotentialSimdSibling(reg, rep);
2127   }
2128   return reg;
2129 }
2130 
InUseBitmap(UsePosition pos)2131 RegisterBitVector SinglePassRegisterAllocator::InUseBitmap(UsePosition pos) {
2132   switch (pos) {
2133     case UsePosition::kStart:
2134       return in_use_at_instr_start_bits_;
2135     case UsePosition::kEnd:
2136       return in_use_at_instr_end_bits_;
2137     case UsePosition::kAll:
2138       return in_use_at_instr_start_bits_.Union(in_use_at_instr_end_bits_);
2139     case UsePosition::kNone:
2140       UNREACHABLE();
2141   }
2142 }
2143 
IsValidForRep(RegisterIndex reg,MachineRepresentation rep)2144 bool SinglePassRegisterAllocator::IsValidForRep(RegisterIndex reg,
2145                                                 MachineRepresentation rep) {
2146   if (kFPAliasing != AliasingKind::kCombine ||
2147       kind() == RegisterKind::kGeneral) {
2148     return true;
2149   } else {
2150     switch (rep) {
2151       case MachineRepresentation::kFloat32:
2152         return index_to_float32_reg_code_->at(reg.ToInt()) != -1;
2153       case MachineRepresentation::kFloat64:
2154         return true;
2155       case MachineRepresentation::kSimd128:
2156         return index_to_simd128_reg_code_->at(reg.ToInt()) != -1;
2157       default:
2158         UNREACHABLE();
2159     }
2160   }
2161 }
2162 
ChooseFreeRegister(MachineRepresentation rep,UsePosition pos)2163 RegisterIndex SinglePassRegisterAllocator::ChooseFreeRegister(
2164     MachineRepresentation rep, UsePosition pos) {
2165   // Take the first free, non-blocked register, if available.
2166   // TODO(rmcilroy): Consider a better heuristic.
2167   RegisterBitVector allocated_or_in_use =
2168       InUseBitmap(pos).Union(allocated_registers_bits_);
2169   return ChooseFreeRegister(allocated_or_in_use, rep);
2170 }
2171 
ChooseFreeRegister(const RegisterBitVector & allocated_regs,MachineRepresentation rep)2172 RegisterIndex SinglePassRegisterAllocator::ChooseFreeRegister(
2173     const RegisterBitVector& allocated_regs, MachineRepresentation rep) {
2174   RegisterIndex chosen_reg = RegisterIndex::Invalid();
2175   if (kFPAliasing != AliasingKind::kCombine ||
2176       kind() == RegisterKind::kGeneral) {
2177     chosen_reg = allocated_regs.GetFirstCleared(num_allocatable_registers_);
2178   } else {
2179     // If we don't have simple fp aliasing, we need to check each register
2180     // individually to get one with the required representation.
2181     for (RegisterIndex reg : *register_state_) {
2182       if (IsValidForRep(reg, rep) && !allocated_regs.Contains(reg, rep)) {
2183         chosen_reg = reg;
2184         break;
2185       }
2186     }
2187   }
2188 
2189   DCHECK_IMPLIES(chosen_reg.is_valid(), IsValidForRep(chosen_reg, rep));
2190   return chosen_reg;
2191 }
2192 
ChooseRegisterToSpill(MachineRepresentation rep,UsePosition pos)2193 RegisterIndex SinglePassRegisterAllocator::ChooseRegisterToSpill(
2194     MachineRepresentation rep, UsePosition pos) {
2195   RegisterBitVector in_use = InUseBitmap(pos);
2196 
2197   // Choose a register that will need to be spilled. Preferentially choose:
2198   //  - A register with only pending uses, to avoid having to add a gap move for
2199   //    a non-pending use.
2200   //  - A register holding a virtual register that has already been spilled, to
2201   //    avoid adding a new gap move to spill the virtual register when it is
2202   //    output.
2203   //  - Prefer the register holding the virtual register with the earliest
2204   //    definition point, since it is more likely to be spilled anyway.
2205   RegisterIndex chosen_reg;
2206   int earliest_definition = kMaxInt;
2207   bool pending_only_use = false;
2208   bool already_spilled = false;
2209   for (RegisterIndex reg : *register_state_) {
2210     // Skip if register is in use, or not valid for representation.
2211     if (!IsValidForRep(reg, rep) || in_use.Contains(reg, rep)) continue;
2212     // With non-simple FP aliasing, a SIMD register might block more than one FP
2213     // register.
2214     DCHECK_IMPLIES(kFPAliasing != AliasingKind::kCombine,
2215                    register_state_->IsAllocated(reg));
2216     if (kFPAliasing == AliasingKind::kCombine &&
2217         !register_state_->IsAllocated(reg))
2218       continue;
2219 
2220     VirtualRegisterData& vreg_data =
2221         VirtualRegisterDataFor(VirtualRegisterForRegister(reg));
2222     if ((!pending_only_use && register_state_->HasPendingUsesOnly(reg)) ||
2223         (!already_spilled && vreg_data.HasSpillOperand()) ||
2224         vreg_data.output_instr_index() < earliest_definition) {
2225       chosen_reg = reg;
2226       earliest_definition = vreg_data.output_instr_index();
2227       pending_only_use = register_state_->HasPendingUsesOnly(reg);
2228       already_spilled = vreg_data.HasSpillOperand();
2229     }
2230   }
2231 
2232   // There should always be an unblocked register available.
2233   DCHECK(chosen_reg.is_valid());
2234   DCHECK(IsValidForRep(chosen_reg, rep));
2235   return chosen_reg;
2236 }
2237 
CommitRegister(RegisterIndex reg,int virtual_register,MachineRepresentation rep,InstructionOperand * operand,UsePosition pos)2238 void SinglePassRegisterAllocator::CommitRegister(RegisterIndex reg,
2239                                                  int virtual_register,
2240                                                  MachineRepresentation rep,
2241                                                  InstructionOperand* operand,
2242                                                  UsePosition pos) {
2243   // Committing the output operation, and mark the register use in this
2244   // instruction, then mark it as free going forward.
2245   AllocatedOperand allocated = AllocatedOperandForReg(reg, rep);
2246   register_state_->Commit(reg, allocated, operand, data_);
2247   MarkRegisterUse(reg, rep, pos);
2248   FreeRegister(reg, virtual_register, rep);
2249   CheckConsistency();
2250 }
2251 
SpillRegister(RegisterIndex reg)2252 void SinglePassRegisterAllocator::SpillRegister(RegisterIndex reg) {
2253   if (!register_state_->IsAllocated(reg)) return;
2254 
2255   // Spill the register and free register.
2256   int virtual_register = VirtualRegisterForRegister(reg);
2257   MachineRepresentation rep = VirtualRegisterDataFor(virtual_register).rep();
2258   AllocatedOperand allocated = AllocatedOperandForReg(reg, rep);
2259   register_state_->Spill(reg, allocated, current_block_, data_);
2260   FreeRegister(reg, virtual_register, rep);
2261 }
2262 
SpillRegisterAndPotentialSimdSibling(RegisterIndex reg,MachineRepresentation rep)2263 void SinglePassRegisterAllocator::SpillRegisterAndPotentialSimdSibling(
2264     RegisterIndex reg, MachineRepresentation rep) {
2265   SpillRegister(reg);
2266 
2267   if (kFPAliasing == AliasingKind::kCombine &&
2268       rep == MachineRepresentation::kSimd128) {
2269     SpillRegister(simdSibling(reg));
2270   }
2271 }
2272 
SpillAllRegisters()2273 void SinglePassRegisterAllocator::SpillAllRegisters() {
2274   if (!register_state_) return;
2275 
2276   for (RegisterIndex reg : *register_state_) {
2277     SpillRegister(reg);
2278   }
2279 }
2280 
SpillRegisterForVirtualRegister(int virtual_register)2281 void SinglePassRegisterAllocator::SpillRegisterForVirtualRegister(
2282     int virtual_register) {
2283   DCHECK_NE(virtual_register, InstructionOperand::kInvalidVirtualRegister);
2284   RegisterIndex reg = RegisterForVirtualRegister(virtual_register);
2285   if (reg.is_valid()) {
2286     SpillRegister(reg);
2287   }
2288 }
2289 
SpillRegisterForDeferred(RegisterIndex reg,int instr_index)2290 void SinglePassRegisterAllocator::SpillRegisterForDeferred(RegisterIndex reg,
2291                                                            int instr_index) {
2292   // Committing the output operation, and mark the register use in this
2293   // instruction, then mark it as free going forward.
2294   if (register_state_->IsAllocated(reg) && register_state_->IsShared(reg)) {
2295     VirtualRegisterData& virtual_register =
2296         data_->VirtualRegisterDataFor(VirtualRegisterForRegister(reg));
2297     AllocatedOperand allocated =
2298         AllocatedOperandForReg(reg, virtual_register.rep());
2299     register_state_->SpillForDeferred(reg, allocated, instr_index, data_);
2300     FreeRegister(reg, virtual_register.vreg(), virtual_register.rep());
2301   }
2302   CheckConsistency();
2303 }
2304 
AllocateDeferredBlockSpillOutput(int instr_index,RpoNumber deferred_block,VirtualRegisterData & virtual_register)2305 void SinglePassRegisterAllocator::AllocateDeferredBlockSpillOutput(
2306     int instr_index, RpoNumber deferred_block,
2307     VirtualRegisterData& virtual_register) {
2308   DCHECK(data_->GetBlock(deferred_block)->IsDeferred());
2309   DCHECK(virtual_register.HasSpillRange());
2310   if (!virtual_register.NeedsSpillAtOutput() &&
2311       !DefinedAfter(virtual_register.vreg(), instr_index, UsePosition::kEnd)) {
2312     // If a register has been assigned to the virtual register, and the virtual
2313     // register still doesn't need to be spilled at it's output, and add a
2314     // pending move to output the virtual register to it's spill slot on entry
2315     // of the deferred block (to avoid spilling on in non-deferred code).
2316     // TODO(rmcilroy): Consider assigning a register even if the virtual
2317     // register isn't yet assigned - currently doing this regresses performance.
2318     RegisterIndex reg = RegisterForVirtualRegister(virtual_register.vreg());
2319     if (reg.is_valid()) {
2320       int deferred_block_start =
2321           data_->GetBlock(deferred_block)->first_instruction_index();
2322       register_state_->MoveToSpillSlotOnDeferred(reg, virtual_register.vreg(),
2323                                                  deferred_block_start, data_);
2324       return;
2325     } else {
2326       virtual_register.MarkAsNeedsSpillAtOutput();
2327     }
2328   }
2329 }
2330 
AllocatedOperandForReg(RegisterIndex reg,MachineRepresentation rep)2331 AllocatedOperand SinglePassRegisterAllocator::AllocatedOperandForReg(
2332     RegisterIndex reg, MachineRepresentation rep) {
2333   return AllocatedOperand(AllocatedOperand::REGISTER, rep, ToRegCode(reg, rep));
2334 }
2335 
AllocateUse(RegisterIndex reg,VirtualRegisterData & virtual_register,InstructionOperand * operand,int instr_index,UsePosition pos)2336 void SinglePassRegisterAllocator::AllocateUse(
2337     RegisterIndex reg, VirtualRegisterData& virtual_register,
2338     InstructionOperand* operand, int instr_index, UsePosition pos) {
2339   DCHECK(IsFreeOrSameVirtualRegister(reg, virtual_register.vreg()));
2340 
2341   AllocatedOperand allocated =
2342       AllocatedOperandForReg(reg, virtual_register.rep());
2343   register_state_->Commit(reg, allocated, operand, data_);
2344   register_state_->AllocateUse(reg, virtual_register.vreg(), operand,
2345                                instr_index, data_);
2346   AssignRegister(reg, virtual_register.vreg(), virtual_register.rep(), pos);
2347   CheckConsistency();
2348 }
2349 
AllocatePendingUse(RegisterIndex reg,VirtualRegisterData & virtual_register,InstructionOperand * operand,bool can_be_constant,int instr_index)2350 void SinglePassRegisterAllocator::AllocatePendingUse(
2351     RegisterIndex reg, VirtualRegisterData& virtual_register,
2352     InstructionOperand* operand, bool can_be_constant, int instr_index) {
2353   DCHECK(IsFreeOrSameVirtualRegister(reg, virtual_register.vreg()));
2354 
2355   register_state_->AllocatePendingUse(reg, virtual_register.vreg(), operand,
2356                                       can_be_constant, instr_index);
2357   // Since this is a pending use and the operand doesn't need to use a register,
2358   // allocate with UsePosition::kNone to avoid blocking it's use by other
2359   // operands in this instruction.
2360   AssignRegister(reg, virtual_register.vreg(), virtual_register.rep(),
2361                  UsePosition::kNone);
2362   CheckConsistency();
2363 }
2364 
AllocateUseWithMove(RegisterIndex reg,VirtualRegisterData & virtual_register,UnallocatedOperand * operand,int instr_index,UsePosition pos)2365 void SinglePassRegisterAllocator::AllocateUseWithMove(
2366     RegisterIndex reg, VirtualRegisterData& virtual_register,
2367     UnallocatedOperand* operand, int instr_index, UsePosition pos) {
2368   AllocatedOperand to = AllocatedOperandForReg(reg, virtual_register.rep());
2369   UnallocatedOperand from =
2370       UnallocatedOperand(UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT,
2371                          virtual_register.vreg());
2372   data_->AddGapMove(instr_index, Instruction::END, from, to);
2373   InstructionOperand::ReplaceWith(operand, &to);
2374   MarkRegisterUse(reg, virtual_register.rep(), pos);
2375   CheckConsistency();
2376 }
2377 
AllocateInput(UnallocatedOperand * operand,VirtualRegisterData & virtual_register,int instr_index)2378 void SinglePassRegisterAllocator::AllocateInput(
2379     UnallocatedOperand* operand, VirtualRegisterData& virtual_register,
2380     int instr_index) {
2381   EnsureRegisterState();
2382 
2383   // Spill slot policy operands.
2384   if (operand->HasFixedSlotPolicy()) {
2385     // If the operand is from a fixed slot, allocate it to that fixed slot,
2386     // then add a gap move from an unconstrained copy of that input operand,
2387     // and spill the gap move's input operand.
2388     // TODO(rmcilroy): We could allocate a register for the gap move however
2389     // we would need to wait until we've done all the allocations for the
2390     // instruction since the allocation needs to reflect the state before
2391     // the instruction (at the gap move). For now spilling is fine since
2392     // fixed slot inputs are uncommon.
2393     UnallocatedOperand input_copy(
2394         UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT,
2395         virtual_register.vreg());
2396     AllocatedOperand allocated =
2397         AllocatedOperand(AllocatedOperand::STACK_SLOT, virtual_register.rep(),
2398                          operand->fixed_slot_index());
2399     InstructionOperand::ReplaceWith(operand, &allocated);
2400     MoveOperands* move_op =
2401         data_->AddGapMove(instr_index, Instruction::END, input_copy, *operand);
2402     virtual_register.SpillOperand(&move_op->source(), instr_index, true, data_);
2403     return;
2404   } else if (operand->HasSlotPolicy()) {
2405     virtual_register.SpillOperand(operand, instr_index, false, data_);
2406     return;
2407   }
2408 
2409   // Otherwise try to allocate a register for the operation.
2410   UsePosition pos =
2411       operand->IsUsedAtStart() ? UsePosition::kStart : UsePosition::kAll;
2412   if (operand->HasFixedRegisterPolicy() ||
2413       operand->HasFixedFPRegisterPolicy()) {
2414     // With a fixed register operand, we must use that register.
2415     RegisterIndex reg =
2416         FromRegCode(operand->fixed_register_index(), virtual_register.rep());
2417     if (!VirtualRegisterIsUnallocatedOrInReg(virtual_register.vreg(), reg)) {
2418       // If the virtual register is already in a different register, then just
2419       // add a gap move from that register to the fixed register.
2420       AllocateUseWithMove(reg, virtual_register, operand, instr_index, pos);
2421     } else {
2422       // Otherwise allocate a use of the fixed register for |virtual_register|.
2423       AllocateUse(reg, virtual_register, operand, instr_index, pos);
2424     }
2425   } else {
2426     bool must_use_register = operand->HasRegisterPolicy();
2427     RegisterIndex reg = ChooseRegisterFor(virtual_register, instr_index, pos,
2428                                           must_use_register);
2429 
2430     if (!reg.is_valid()) {
2431       // The register will have been spilled at this use.
2432       virtual_register.SpillOperand(
2433           operand, instr_index, operand->HasRegisterOrSlotOrConstantPolicy(),
2434           data_);
2435     } else if (!must_use_register) {
2436       // We might later dedice to spill this register; allocate a pending use.
2437       AllocatePendingUse(reg, virtual_register, operand,
2438                          operand->HasRegisterOrSlotOrConstantPolicy(),
2439                          instr_index);
2440     } else if (VirtualRegisterIsUnallocatedOrInReg(virtual_register.vreg(),
2441                                                    reg)) {
2442       // The register is directly usable.
2443       AllocateUse(reg, virtual_register, operand, instr_index, pos);
2444     } else {
2445       // We assigned another register to the vreg before. {ChooseRegisterFor}
2446       // chose a different one (e.g. to fulfill a "unique register" constraint
2447       // for a vreg that was previously used for the input corresponding to the
2448       // "same as input" output), so add a gap move to copy the input value to
2449       // that new register.
2450       AllocateUseWithMove(reg, virtual_register, operand, instr_index, pos);
2451     }
2452   }
2453 }
2454 
AllocateGapMoveInput(UnallocatedOperand * operand,VirtualRegisterData & vreg_data,int instr_index)2455 void SinglePassRegisterAllocator::AllocateGapMoveInput(
2456     UnallocatedOperand* operand, VirtualRegisterData& vreg_data,
2457     int instr_index) {
2458   EnsureRegisterState();
2459   // Gap move inputs should be unconstrained.
2460   DCHECK(operand->HasRegisterOrSlotOrConstantPolicy());
2461   RegisterIndex reg =
2462       ChooseRegisterFor(vreg_data, instr_index, UsePosition::kStart, false);
2463   if (reg.is_valid()) {
2464     AllocatePendingUse(reg, vreg_data, operand, true, instr_index);
2465   } else {
2466     vreg_data.SpillOperand(operand, instr_index, true, data_);
2467   }
2468 }
2469 
AllocateConstantOutput(ConstantOperand * operand,VirtualRegisterData & vreg_data,int instr_index)2470 void SinglePassRegisterAllocator::AllocateConstantOutput(
2471     ConstantOperand* operand, VirtualRegisterData& vreg_data, int instr_index) {
2472   EnsureRegisterState();
2473   // If the constant is allocated to a register, spill it now to add the
2474   // necessary gap moves from the constant operand to the register.
2475   SpillRegisterForVirtualRegister(vreg_data.vreg());
2476   if (vreg_data.NeedsSpillAtOutput()) {
2477     vreg_data.EmitGapMoveFromOutputToSpillSlot(*operand, current_block_,
2478                                                instr_index, data_);
2479   }
2480 }
2481 
AllocateOutput(UnallocatedOperand * operand,VirtualRegisterData & vreg_data,int instr_index)2482 void SinglePassRegisterAllocator::AllocateOutput(UnallocatedOperand* operand,
2483                                                  VirtualRegisterData& vreg_data,
2484                                                  int instr_index) {
2485   AllocateOutput(operand, vreg_data, instr_index, UsePosition::kEnd);
2486 }
2487 
AllocateOutput(UnallocatedOperand * operand,VirtualRegisterData & vreg_data,int instr_index,UsePosition pos)2488 RegisterIndex SinglePassRegisterAllocator::AllocateOutput(
2489     UnallocatedOperand* operand, VirtualRegisterData& vreg_data,
2490     int instr_index, UsePosition pos) {
2491   EnsureRegisterState();
2492   int virtual_register = vreg_data.vreg();
2493 
2494   RegisterIndex reg;
2495   if (operand->HasSlotPolicy() || operand->HasFixedSlotPolicy()) {
2496     // We can't allocate a register for output given the policy, so make sure
2497     // to spill the register holding this virtual register if any.
2498     SpillRegisterForVirtualRegister(virtual_register);
2499     reg = RegisterIndex::Invalid();
2500   } else if (operand->HasFixedPolicy()) {
2501     reg = FromRegCode(operand->fixed_register_index(), vreg_data.rep());
2502   } else {
2503     reg = ChooseRegisterFor(vreg_data, instr_index, pos,
2504                             operand->HasRegisterPolicy());
2505   }
2506 
2507   // TODO(rmcilroy): support secondary storage.
2508   if (!reg.is_valid()) {
2509     vreg_data.SpillOperand(operand, instr_index, false, data_);
2510   } else {
2511     InstructionOperand move_output_to;
2512     if (!VirtualRegisterIsUnallocatedOrInReg(virtual_register, reg)) {
2513       // If the |virtual register| was in a different register (e.g., due to
2514       // the output having a fixed register), then commit its use in that
2515       // register here, and move it from the output operand below.
2516       RegisterIndex existing_reg = RegisterForVirtualRegister(virtual_register);
2517       // Don't mark |existing_reg| as used in this instruction, since it is used
2518       // in the (already allocated) following instruction's gap-move.
2519       CommitRegister(existing_reg, vreg_data.vreg(), vreg_data.rep(),
2520                      &move_output_to, UsePosition::kNone);
2521     }
2522     CommitRegister(reg, vreg_data.vreg(), vreg_data.rep(), operand, pos);
2523     if (move_output_to.IsAllocated()) {
2524       // Emit a move from output to the register that the |virtual_register| was
2525       // allocated to.
2526       EmitGapMoveFromOutput(*operand, move_output_to, instr_index);
2527     }
2528     if (vreg_data.NeedsSpillAtOutput()) {
2529       vreg_data.EmitGapMoveFromOutputToSpillSlot(
2530           *AllocatedOperand::cast(operand), current_block_, instr_index, data_);
2531     } else if (vreg_data.NeedsSpillAtDeferredBlocks()) {
2532       vreg_data.EmitDeferredSpillOutputs(data_);
2533     }
2534   }
2535 
2536   return reg;
2537 }
2538 
AllocateSameInputOutput(UnallocatedOperand * output,UnallocatedOperand * input,VirtualRegisterData & output_vreg_data,VirtualRegisterData & input_vreg_data,int instr_index)2539 void SinglePassRegisterAllocator::AllocateSameInputOutput(
2540     UnallocatedOperand* output, UnallocatedOperand* input,
2541     VirtualRegisterData& output_vreg_data, VirtualRegisterData& input_vreg_data,
2542     int instr_index) {
2543   EnsureRegisterState();
2544   int input_vreg = input_vreg_data.vreg();
2545   int output_vreg = output_vreg_data.vreg();
2546 
2547   // The input operand has the details of the register constraints, so replace
2548   // the output operand with a copy of the input, with the output's vreg.
2549   UnallocatedOperand output_as_input(*input, output_vreg);
2550   InstructionOperand::ReplaceWith(output, &output_as_input);
2551   RegisterIndex reg =
2552       AllocateOutput(output, output_vreg_data, instr_index, UsePosition::kAll);
2553 
2554   if (reg.is_valid()) {
2555     // Replace the input operand with an unallocated fixed register policy for
2556     // the same register.
2557     UnallocatedOperand::ExtendedPolicy policy =
2558         kind() == RegisterKind::kGeneral
2559             ? UnallocatedOperand::FIXED_REGISTER
2560             : UnallocatedOperand::FIXED_FP_REGISTER;
2561     MachineRepresentation rep = input_vreg_data.rep();
2562     UnallocatedOperand fixed_input(policy, ToRegCode(reg, rep), input_vreg);
2563     InstructionOperand::ReplaceWith(input, &fixed_input);
2564     same_input_output_registers_bits_.Add(reg, rep);
2565   } else {
2566     // Output was spilled. Due to the SameAsInput allocation policy, we need to
2567     // make the input operand the same as the output, i.e., the output virtual
2568     // register's spill slot. As such, spill this input operand using the output
2569     // virtual register's spill slot, then add a gap-move to move the input
2570     // value into this spill slot.
2571     output_vreg_data.SpillOperand(input, instr_index, false, data_);
2572 
2573     // Add an unconstrained gap move for the input virtual register.
2574     UnallocatedOperand unconstrained_input(
2575         UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT, input_vreg);
2576     MoveOperands* move_ops = data_->AddGapMove(
2577         instr_index, Instruction::END, unconstrained_input, PendingOperand());
2578     output_vreg_data.SpillOperand(&move_ops->destination(), instr_index, true,
2579                                   data_);
2580   }
2581 }
2582 
AllocateTemp(UnallocatedOperand * operand,int virtual_register,MachineRepresentation rep,int instr_index)2583 void SinglePassRegisterAllocator::AllocateTemp(UnallocatedOperand* operand,
2584                                                int virtual_register,
2585                                                MachineRepresentation rep,
2586                                                int instr_index) {
2587   EnsureRegisterState();
2588   RegisterIndex reg;
2589   DCHECK(!operand->HasFixedSlotPolicy());
2590   if (operand->HasSlotPolicy()) {
2591     reg = RegisterIndex::Invalid();
2592   } else if (operand->HasFixedRegisterPolicy() ||
2593              operand->HasFixedFPRegisterPolicy()) {
2594     reg = FromRegCode(operand->fixed_register_index(), rep);
2595   } else {
2596     reg =
2597         ChooseRegisterFor(rep, UsePosition::kAll, operand->HasRegisterPolicy());
2598   }
2599 
2600   if (reg.is_valid()) {
2601     DCHECK(virtual_register == InstructionOperand::kInvalidVirtualRegister ||
2602            VirtualRegisterIsUnallocatedOrInReg(virtual_register, reg));
2603     CommitRegister(reg, virtual_register, rep, operand, UsePosition::kAll);
2604   } else {
2605     VirtualRegisterData& vreg_data = VirtualRegisterDataFor(virtual_register);
2606     vreg_data.SpillOperand(operand, instr_index,
2607                            operand->HasRegisterOrSlotOrConstantPolicy(), data_);
2608   }
2609 }
2610 
DefinedAfter(int virtual_register,int instr_index,UsePosition pos)2611 bool SinglePassRegisterAllocator::DefinedAfter(int virtual_register,
2612                                                int instr_index,
2613                                                UsePosition pos) {
2614   if (virtual_register == InstructionOperand::kInvalidVirtualRegister)
2615     return false;
2616   int defined_at =
2617       VirtualRegisterDataFor(virtual_register).output_instr_index();
2618   return defined_at > instr_index ||
2619          (defined_at == instr_index && pos == UsePosition::kStart);
2620 }
2621 
ReserveFixedInputRegister(const UnallocatedOperand * operand,int virtual_register,MachineRepresentation rep,int instr_index)2622 void SinglePassRegisterAllocator::ReserveFixedInputRegister(
2623     const UnallocatedOperand* operand, int virtual_register,
2624     MachineRepresentation rep, int instr_index) {
2625   ReserveFixedRegister(
2626       operand, virtual_register, rep, instr_index,
2627       operand->IsUsedAtStart() ? UsePosition::kStart : UsePosition::kAll);
2628 }
2629 
ReserveFixedTempRegister(const UnallocatedOperand * operand,int virtual_register,MachineRepresentation rep,int instr_index)2630 void SinglePassRegisterAllocator::ReserveFixedTempRegister(
2631     const UnallocatedOperand* operand, int virtual_register,
2632     MachineRepresentation rep, int instr_index) {
2633   ReserveFixedRegister(operand, virtual_register, rep, instr_index,
2634                        UsePosition::kAll);
2635 }
2636 
ReserveFixedOutputRegister(const UnallocatedOperand * operand,int virtual_register,MachineRepresentation rep,int instr_index)2637 void SinglePassRegisterAllocator::ReserveFixedOutputRegister(
2638     const UnallocatedOperand* operand, int virtual_register,
2639     MachineRepresentation rep, int instr_index) {
2640   ReserveFixedRegister(operand, virtual_register, rep, instr_index,
2641                        UsePosition::kEnd);
2642 }
2643 
ReserveFixedRegister(const UnallocatedOperand * operand,int virtual_register,MachineRepresentation rep,int instr_index,UsePosition pos)2644 void SinglePassRegisterAllocator::ReserveFixedRegister(
2645     const UnallocatedOperand* operand, int virtual_register,
2646     MachineRepresentation rep, int instr_index, UsePosition pos) {
2647   EnsureRegisterState();
2648   int reg_code = operand->fixed_register_index();
2649   RegisterIndex reg = FromRegCode(reg_code, rep);
2650   if (!IsFreeOrSameVirtualRegister(reg, virtual_register) &&
2651       !DefinedAfter(virtual_register, instr_index, pos)) {
2652     // If register is in-use by a different virtual register, spill it now.
2653     // TODO(rmcilroy): Consider moving to a unconstrained register instead of
2654     // spilling.
2655     SpillRegister(reg);
2656   }
2657   // Also potentially spill the "sibling SIMD register" on architectures where a
2658   // SIMD register aliases two FP registers.
2659   if (kFPAliasing == AliasingKind::kCombine &&
2660       rep == MachineRepresentation::kSimd128) {
2661     if (register_state_->IsAllocated(simdSibling(reg)) &&
2662         !DefinedAfter(virtual_register, instr_index, pos)) {
2663       SpillRegister(simdSibling(reg));
2664     }
2665   }
2666   // Similarly (but the other way around), spill a SIMD register that (partly)
2667   // overlaps with a fixed FP register.
2668   if (kFPAliasing == AliasingKind::kCombine &&
2669       (rep == MachineRepresentation::kFloat64 ||
2670        rep == MachineRepresentation::kFloat32)) {
2671     int simd_reg_code;
2672     CHECK_EQ(
2673         1, data_->config()->GetAliases(
2674                rep, reg_code, MachineRepresentation::kSimd128, &simd_reg_code));
2675     // Sanity check: The SIMD register code should be the shifted {reg_code}.
2676     DCHECK_EQ(simd_reg_code,
2677               reg_code >> (rep == MachineRepresentation::kFloat64 ? 1 : 2));
2678     RegisterIndex simd_reg =
2679         FromRegCode(simd_reg_code, MachineRepresentation::kSimd128);
2680     DCHECK(simd_reg == reg || simdSibling(simd_reg) == reg);
2681     int allocated_vreg = VirtualRegisterForRegister(simd_reg);
2682     if (simd_reg != reg &&
2683         allocated_vreg != InstructionOperand::kInvalidVirtualRegister &&
2684         VirtualRegisterDataFor(allocated_vreg).rep() ==
2685             MachineRepresentation::kSimd128 &&
2686         !DefinedAfter(virtual_register, instr_index, pos)) {
2687       SpillRegister(simd_reg);
2688     }
2689   }
2690 
2691   MarkRegisterUse(reg, rep, pos);
2692 }
2693 
AllocatePhiGapMove(VirtualRegisterData & to_vreg,VirtualRegisterData & from_vreg,int instr_index)2694 void SinglePassRegisterAllocator::AllocatePhiGapMove(
2695     VirtualRegisterData& to_vreg, VirtualRegisterData& from_vreg,
2696     int instr_index) {
2697   EnsureRegisterState();
2698   RegisterIndex from_register = RegisterForVirtualRegister(from_vreg.vreg());
2699   RegisterIndex to_register = RegisterForVirtualRegister(to_vreg.vreg());
2700 
2701   // If to_register isn't marked as a phi gap move, we can't use it as such.
2702   if (to_register.is_valid() && !register_state_->IsPhiGapMove(to_register)) {
2703     to_register = RegisterIndex::Invalid();
2704   }
2705 
2706   if (to_register.is_valid() && !from_register.is_valid()) {
2707     // If |to| virtual register is allocated to a register, and the |from|
2708     // virtual register isn't allocated, then commit this register and
2709     // re-allocate it to the |from| virtual register.
2710     InstructionOperand operand;
2711     CommitRegister(to_register, to_vreg.vreg(), to_vreg.rep(), &operand,
2712                    UsePosition::kAll);
2713     AllocateUse(to_register, from_vreg, &operand, instr_index,
2714                 UsePosition::kAll);
2715   } else {
2716     // Otherwise add a gap move.
2717     MoveOperands* move =
2718         data_->AddPendingOperandGapMove(instr_index, Instruction::END);
2719     PendingOperand* to_operand = PendingOperand::cast(&move->destination());
2720     PendingOperand* from_operand = PendingOperand::cast(&move->source());
2721 
2722     // Commit the |to| side to either a register or the pending spills.
2723     if (to_register.is_valid()) {
2724       CommitRegister(to_register, to_vreg.vreg(), to_vreg.rep(), to_operand,
2725                      UsePosition::kAll);
2726     } else {
2727       to_vreg.SpillOperand(to_operand, instr_index, true, data_);
2728     }
2729 
2730     // The from side is unconstrained.
2731     UnallocatedOperand unconstrained_input(
2732         UnallocatedOperand::REGISTER_OR_SLOT_OR_CONSTANT, from_vreg.vreg());
2733     InstructionOperand::ReplaceWith(from_operand, &unconstrained_input);
2734   }
2735 }
2736 
AllocatePhi(VirtualRegisterData & virtual_register,const InstructionBlock * block)2737 void SinglePassRegisterAllocator::AllocatePhi(
2738     VirtualRegisterData& virtual_register, const InstructionBlock* block) {
2739   if (virtual_register.NeedsSpillAtOutput() || block->IsLoopHeader()) {
2740     // If the Phi needs to be spilled, just spill here directly so that all
2741     // gap moves into the Phi move into the spill slot.
2742     SpillRegisterForVirtualRegister(virtual_register.vreg());
2743   } else {
2744     RegisterIndex reg = RegisterForVirtualRegister(virtual_register.vreg());
2745     if (reg.is_valid()) {
2746       // If the register is valid, assign it as a phi gap move to be processed
2747       // at the successor blocks. If no register or spill slot was used then
2748       // the virtual register was never used.
2749       register_state_->UseForPhiGapMove(reg);
2750     }
2751   }
2752 }
2753 
EnsureRegisterState()2754 void SinglePassRegisterAllocator::EnsureRegisterState() {
2755   if (V8_UNLIKELY(!register_state_)) {
2756     register_state_ = RegisterState::New(kind(), num_allocatable_registers_,
2757                                          data_->allocation_zone());
2758   }
2759 }
2760 
2761 class MidTierOutputProcessor final {
2762  public:
2763   explicit MidTierOutputProcessor(MidTierRegisterAllocationData* data);
2764 
2765   void InitializeBlockState(const InstructionBlock* block);
2766   void DefineOutputs(const InstructionBlock* block);
2767 
2768  private:
2769   void PopulateDeferredBlockRegion(RpoNumber initial_block);
2770 
VirtualRegisterDataFor(int virtual_register) const2771   VirtualRegisterData& VirtualRegisterDataFor(int virtual_register) const {
2772     return data_->VirtualRegisterDataFor(virtual_register);
2773   }
RepresentationFor(int virtual_register) const2774   MachineRepresentation RepresentationFor(int virtual_register) const {
2775     DCHECK_NE(virtual_register, InstructionOperand::kInvalidVirtualRegister);
2776     DCHECK_LT(virtual_register, code()->VirtualRegisterCount());
2777     return code()->GetRepresentation(virtual_register);
2778   }
2779 
IsDeferredBlockBoundary(const ZoneVector<RpoNumber> & blocks)2780   bool IsDeferredBlockBoundary(const ZoneVector<RpoNumber>& blocks) {
2781     return blocks.size() == 1 && !data_->GetBlock(blocks[0])->IsDeferred();
2782   }
2783 
code() const2784   InstructionSequence* code() const { return data_->code(); }
zone() const2785   Zone* zone() const { return data_->allocation_zone(); }
2786 
2787   MidTierRegisterAllocationData* const data_;
2788   ZoneQueue<RpoNumber> deferred_blocks_worklist_;
2789   ZoneSet<RpoNumber> deferred_blocks_processed_;
2790 };
2791 
MidTierOutputProcessor(MidTierRegisterAllocationData * data)2792 MidTierOutputProcessor::MidTierOutputProcessor(
2793     MidTierRegisterAllocationData* data)
2794     : data_(data),
2795       deferred_blocks_worklist_(data->allocation_zone()),
2796       deferred_blocks_processed_(data->allocation_zone()) {}
2797 
PopulateDeferredBlockRegion(RpoNumber initial_block)2798 void MidTierOutputProcessor::PopulateDeferredBlockRegion(
2799     RpoNumber initial_block) {
2800   DeferredBlocksRegion* deferred_blocks_region =
2801       zone()->New<DeferredBlocksRegion>(zone(),
2802                                         code()->InstructionBlockCount());
2803   DCHECK(deferred_blocks_worklist_.empty());
2804   deferred_blocks_worklist_.push(initial_block);
2805   deferred_blocks_processed_.insert(initial_block);
2806   while (!deferred_blocks_worklist_.empty()) {
2807     RpoNumber current = deferred_blocks_worklist_.front();
2808     deferred_blocks_worklist_.pop();
2809     deferred_blocks_region->AddBlock(current, data_);
2810 
2811     const InstructionBlock* curr_block = data_->GetBlock(current);
2812     // Check for whether the predecessor blocks are still deferred.
2813     if (IsDeferredBlockBoundary(curr_block->predecessors())) {
2814       // If not, mark the predecessor as having a deferred successor.
2815       data_->block_state(curr_block->predecessors()[0])
2816           .MarkAsDeferredBlockBoundary();
2817     } else {
2818       // Otherwise process predecessors.
2819       for (RpoNumber pred : curr_block->predecessors()) {
2820         if (deferred_blocks_processed_.count(pred) == 0) {
2821           deferred_blocks_worklist_.push(pred);
2822           deferred_blocks_processed_.insert(pred);
2823         }
2824       }
2825     }
2826 
2827     // Check for whether the successor blocks are still deferred.
2828     // Process any unprocessed successors if we aren't at a boundary.
2829     if (IsDeferredBlockBoundary(curr_block->successors())) {
2830       // If not, mark the predecessor as having a deferred successor.
2831       data_->block_state(current).MarkAsDeferredBlockBoundary();
2832     } else {
2833       // Otherwise process successors.
2834       for (RpoNumber succ : curr_block->successors()) {
2835         if (deferred_blocks_processed_.count(succ) == 0) {
2836           deferred_blocks_worklist_.push(succ);
2837           deferred_blocks_processed_.insert(succ);
2838         }
2839       }
2840     }
2841   }
2842 }
2843 
InitializeBlockState(const InstructionBlock * block)2844 void MidTierOutputProcessor::InitializeBlockState(
2845     const InstructionBlock* block) {
2846   // Update our predecessor blocks with their successors_phi_index if we have
2847   // phis.
2848   if (block->phis().size()) {
2849     for (int i = 0; i < static_cast<int>(block->PredecessorCount()); ++i) {
2850       data_->block_state(block->predecessors()[i]).set_successors_phi_index(i);
2851     }
2852   }
2853 
2854   BlockState& block_state = data_->block_state(block->rpo_number());
2855 
2856   if (block->IsDeferred() && !block_state.deferred_blocks_region()) {
2857     PopulateDeferredBlockRegion(block->rpo_number());
2858   }
2859 
2860   // Mark this block as dominating itself.
2861   block_state.dominated_blocks()->Add(block->rpo_number().ToInt());
2862 
2863   if (block->dominator().IsValid()) {
2864     // Add all the blocks this block dominates to its dominator.
2865     BlockState& dominator_block_state = data_->block_state(block->dominator());
2866     dominator_block_state.dominated_blocks()->Union(
2867         *block_state.dominated_blocks());
2868   } else {
2869     // Only the first block shouldn't have a dominator.
2870     DCHECK_EQ(block, code()->instruction_blocks().front());
2871   }
2872 }
2873 
DefineOutputs(const InstructionBlock * block)2874 void MidTierOutputProcessor::DefineOutputs(const InstructionBlock* block) {
2875   int block_start = block->first_instruction_index();
2876   bool is_deferred = block->IsDeferred();
2877 
2878   for (int index = block->last_instruction_index(); index >= block_start;
2879        index--) {
2880     Instruction* instr = code()->InstructionAt(index);
2881 
2882     // For each instruction, define details of the output with the associated
2883     // virtual register data.
2884     for (size_t i = 0; i < instr->OutputCount(); i++) {
2885       InstructionOperand* output = instr->OutputAt(i);
2886       if (output->IsConstant()) {
2887         ConstantOperand* constant_operand = ConstantOperand::cast(output);
2888         int virtual_register = constant_operand->virtual_register();
2889         MachineRepresentation rep = RepresentationFor(virtual_register);
2890         VirtualRegisterDataFor(virtual_register)
2891             .DefineAsConstantOperand(constant_operand, rep, index, is_deferred);
2892       } else {
2893         DCHECK(output->IsUnallocated());
2894         UnallocatedOperand* unallocated_operand =
2895             UnallocatedOperand::cast(output);
2896         int virtual_register = unallocated_operand->virtual_register();
2897         MachineRepresentation rep = RepresentationFor(virtual_register);
2898         bool is_exceptional_call_output =
2899             instr->IsCallWithDescriptorFlags() &&
2900             instr->HasCallDescriptorFlag(CallDescriptor::kHasExceptionHandler);
2901         if (unallocated_operand->HasFixedSlotPolicy()) {
2902           // If output has a fixed slot policy, allocate its spill operand now
2903           // so that the register allocator can use this knowledge.
2904           AllocatedOperand* fixed_spill_operand =
2905               AllocatedOperand::New(zone(), AllocatedOperand::STACK_SLOT, rep,
2906                                     unallocated_operand->fixed_slot_index());
2907           VirtualRegisterDataFor(virtual_register)
2908               .DefineAsFixedSpillOperand(fixed_spill_operand, virtual_register,
2909                                          rep, index, is_deferred,
2910                                          is_exceptional_call_output);
2911         } else {
2912           VirtualRegisterDataFor(virtual_register)
2913               .DefineAsUnallocatedOperand(virtual_register, rep, index,
2914                                           is_deferred,
2915                                           is_exceptional_call_output);
2916         }
2917       }
2918     }
2919 
2920     // Mark any instructions that require reference maps for later reference map
2921     // processing.
2922     if (instr->HasReferenceMap()) {
2923       data_->reference_map_instructions().push_back(index);
2924     }
2925   }
2926 
2927   // Define phi output operands.
2928   for (PhiInstruction* phi : block->phis()) {
2929     int virtual_register = phi->virtual_register();
2930     MachineRepresentation rep = RepresentationFor(virtual_register);
2931     VirtualRegisterDataFor(virtual_register)
2932         .DefineAsPhi(virtual_register, rep, block->first_instruction_index(),
2933                      is_deferred);
2934   }
2935 }
2936 
DefineOutputs(MidTierRegisterAllocationData * data)2937 void DefineOutputs(MidTierRegisterAllocationData* data) {
2938   MidTierOutputProcessor processor(data);
2939 
2940   for (const InstructionBlock* block :
2941        base::Reversed(data->code()->instruction_blocks())) {
2942     data->tick_counter()->TickAndMaybeEnterSafepoint();
2943 
2944     processor.InitializeBlockState(block);
2945     processor.DefineOutputs(block);
2946   }
2947 }
2948 
2949 class MidTierRegisterAllocator final {
2950  public:
2951   explicit MidTierRegisterAllocator(MidTierRegisterAllocationData* data);
2952   MidTierRegisterAllocator(const MidTierRegisterAllocator&) = delete;
2953   MidTierRegisterAllocator& operator=(const MidTierRegisterAllocator&) = delete;
2954 
2955   void AllocateRegisters(const InstructionBlock* block);
2956   void UpdateSpillRangesForLoops();
2957 
general_reg_allocator()2958   SinglePassRegisterAllocator& general_reg_allocator() {
2959     return general_reg_allocator_;
2960   }
double_reg_allocator()2961   SinglePassRegisterAllocator& double_reg_allocator() {
2962     return double_reg_allocator_;
2963   }
2964 
2965  private:
2966   void AllocatePhis(const InstructionBlock* block);
2967   void AllocatePhiGapMoves(const InstructionBlock* block);
2968 
2969   bool IsFixedRegisterPolicy(const UnallocatedOperand* operand);
2970   void ReserveFixedRegisters(int instr_index);
2971 
2972   SinglePassRegisterAllocator& AllocatorFor(MachineRepresentation rep);
2973 
VirtualRegisterDataFor(int virtual_register) const2974   VirtualRegisterData& VirtualRegisterDataFor(int virtual_register) const {
2975     return data_->VirtualRegisterDataFor(virtual_register);
2976   }
code() const2977   InstructionSequence* code() const { return data_->code(); }
allocation_zone() const2978   Zone* allocation_zone() const { return data_->allocation_zone(); }
2979 
2980   MidTierRegisterAllocationData* const data_;
2981   SinglePassRegisterAllocator general_reg_allocator_;
2982   SinglePassRegisterAllocator double_reg_allocator_;
2983 };
2984 
MidTierRegisterAllocator(MidTierRegisterAllocationData * data)2985 MidTierRegisterAllocator::MidTierRegisterAllocator(
2986     MidTierRegisterAllocationData* data)
2987     : data_(data),
2988       general_reg_allocator_(RegisterKind::kGeneral, data),
2989       double_reg_allocator_(RegisterKind::kDouble, data) {}
2990 
AllocateRegisters(const InstructionBlock * block)2991 void MidTierRegisterAllocator::AllocateRegisters(
2992     const InstructionBlock* block) {
2993   RpoNumber block_rpo = block->rpo_number();
2994   bool is_deferred_block_boundary =
2995       data_->block_state(block_rpo).is_deferred_block_boundary();
2996 
2997   general_reg_allocator_.StartBlock(block);
2998   double_reg_allocator_.StartBlock(block);
2999 
3000   // If the block is not deferred but has deferred successors, then try to
3001   // output spill slots for virtual_registers that are only spilled in the
3002   // deferred blocks at the start of those deferred blocks to avoid spilling
3003   // them at their output in non-deferred blocks.
3004   if (is_deferred_block_boundary && !block->IsDeferred()) {
3005     for (RpoNumber successor : block->successors()) {
3006       if (!data_->GetBlock(successor)->IsDeferred()) continue;
3007       DCHECK_GT(successor, block_rpo);
3008       DeferredBlocksRegion* deferred_region =
3009           data_->block_state(successor).deferred_blocks_region();
3010       // Freeze the deferred spills on the region to ensure no more are added to
3011       // this region after the spills for this entry point have already been
3012       // emitted.
3013       deferred_region->FreezeDeferredSpills();
3014       for (const int virtual_register : *deferred_region) {
3015         VirtualRegisterData& vreg_data =
3016             VirtualRegisterDataFor(virtual_register);
3017         AllocatorFor(vreg_data.rep())
3018             .AllocateDeferredBlockSpillOutput(block->last_instruction_index(),
3019                                               successor, vreg_data);
3020       }
3021     }
3022   }
3023 
3024   // Allocate registers for instructions in reverse, from the end of the block
3025   // to the start.
3026   int block_start = block->first_instruction_index();
3027   for (int instr_index = block->last_instruction_index();
3028        instr_index >= block_start; instr_index--) {
3029     Instruction* instr = code()->InstructionAt(instr_index);
3030 
3031     // Reserve any fixed register operands to prevent the register being
3032     // allocated to another operand.
3033     ReserveFixedRegisters(instr_index);
3034 
3035     // Allocate outputs.
3036     for (size_t i = 0; i < instr->OutputCount(); i++) {
3037       InstructionOperand* output = instr->OutputAt(i);
3038       DCHECK(!output->IsAllocated());
3039       if (output->IsConstant()) {
3040         ConstantOperand* constant_operand = ConstantOperand::cast(output);
3041         VirtualRegisterData& vreg_data =
3042             VirtualRegisterDataFor(constant_operand->virtual_register());
3043         AllocatorFor(vreg_data.rep())
3044             .AllocateConstantOutput(constant_operand, vreg_data, instr_index);
3045       } else {
3046         UnallocatedOperand* unallocated_output =
3047             UnallocatedOperand::cast(output);
3048         VirtualRegisterData& output_vreg_data =
3049             VirtualRegisterDataFor(unallocated_output->virtual_register());
3050 
3051         if (unallocated_output->HasSameAsInputPolicy()) {
3052           DCHECK_EQ(i, 0);
3053           UnallocatedOperand* unallocated_input = UnallocatedOperand::cast(
3054               instr->InputAt(unallocated_output->input_index()));
3055           VirtualRegisterData& input_vreg_data =
3056               VirtualRegisterDataFor(unallocated_input->virtual_register());
3057           DCHECK_EQ(AllocatorFor(output_vreg_data.rep()).kind(),
3058                     AllocatorFor(input_vreg_data.rep()).kind());
3059           AllocatorFor(output_vreg_data.rep())
3060               .AllocateSameInputOutput(unallocated_output, unallocated_input,
3061                                        output_vreg_data, input_vreg_data,
3062                                        instr_index);
3063         } else {
3064           AllocatorFor(output_vreg_data.rep())
3065               .AllocateOutput(unallocated_output, output_vreg_data,
3066                               instr_index);
3067         }
3068       }
3069     }
3070 
3071     if (instr->ClobbersRegisters()) {
3072       general_reg_allocator_.SpillAllRegisters();
3073     }
3074     if (instr->ClobbersDoubleRegisters()) {
3075       double_reg_allocator_.SpillAllRegisters();
3076     }
3077 
3078     // Allocate temporaries.
3079     for (size_t i = 0; i < instr->TempCount(); i++) {
3080       UnallocatedOperand* temp = UnallocatedOperand::cast(instr->TempAt(i));
3081       int virtual_register = temp->virtual_register();
3082       MachineRepresentation rep =
3083           virtual_register == InstructionOperand::kInvalidVirtualRegister
3084               ? InstructionSequence::DefaultRepresentation()
3085               : code()->GetRepresentation(virtual_register);
3086       AllocatorFor(rep).AllocateTemp(temp, virtual_register, rep, instr_index);
3087     }
3088 
3089     // Allocate inputs that are used across the whole instruction.
3090     for (size_t i = 0; i < instr->InputCount(); i++) {
3091       if (!instr->InputAt(i)->IsUnallocated()) continue;
3092       UnallocatedOperand* input = UnallocatedOperand::cast(instr->InputAt(i));
3093       if (input->IsUsedAtStart()) continue;
3094       VirtualRegisterData& vreg_data =
3095           VirtualRegisterDataFor(input->virtual_register());
3096       AllocatorFor(vreg_data.rep())
3097           .AllocateInput(input, vreg_data, instr_index);
3098     }
3099 
3100     // Then allocate inputs that are only used at the start of the instruction.
3101     for (size_t i = 0; i < instr->InputCount(); i++) {
3102       if (!instr->InputAt(i)->IsUnallocated()) continue;
3103       UnallocatedOperand* input = UnallocatedOperand::cast(instr->InputAt(i));
3104       DCHECK(input->IsUsedAtStart());
3105       VirtualRegisterData& vreg_data =
3106           VirtualRegisterDataFor(input->virtual_register());
3107       AllocatorFor(vreg_data.rep())
3108           .AllocateInput(input, vreg_data, instr_index);
3109     }
3110 
3111     // If we are allocating for the last instruction in the block, allocate any
3112     // phi gap move operations that are needed to resolve phis in our successor.
3113     if (instr_index == block->last_instruction_index()) {
3114       AllocatePhiGapMoves(block);
3115 
3116       // If this block is deferred but it's successor isn't, update the state to
3117       // limit spills to the deferred blocks where possible.
3118       if (is_deferred_block_boundary && block->IsDeferred()) {
3119         general_reg_allocator_.UpdateForDeferredBlock(instr_index);
3120         double_reg_allocator_.UpdateForDeferredBlock(instr_index);
3121       }
3122     }
3123 
3124     // Allocate any unallocated gap move inputs.
3125     ParallelMove* moves = instr->GetParallelMove(Instruction::END);
3126     if (moves != nullptr) {
3127       for (MoveOperands* move : *moves) {
3128         DCHECK(!move->destination().IsUnallocated());
3129         if (move->source().IsUnallocated()) {
3130           UnallocatedOperand* source =
3131               UnallocatedOperand::cast(&move->source());
3132           VirtualRegisterData& vreg_data =
3133               VirtualRegisterDataFor(source->virtual_register());
3134           AllocatorFor(vreg_data.rep())
3135               .AllocateGapMoveInput(source, vreg_data, instr_index);
3136         }
3137       }
3138     }
3139 
3140     general_reg_allocator_.EndInstruction();
3141     double_reg_allocator_.EndInstruction();
3142   }
3143 
3144   // For now we spill all registers at a loop header.
3145   // TODO(rmcilroy): Add support for register allocations across loops.
3146   if (block->IsLoopHeader()) {
3147     general_reg_allocator_.SpillAllRegisters();
3148     double_reg_allocator_.SpillAllRegisters();
3149   }
3150 
3151   AllocatePhis(block);
3152 
3153   general_reg_allocator_.EndBlock(block);
3154   double_reg_allocator_.EndBlock(block);
3155 }
3156 
AllocatorFor(MachineRepresentation rep)3157 SinglePassRegisterAllocator& MidTierRegisterAllocator::AllocatorFor(
3158     MachineRepresentation rep) {
3159   return IsFloatingPoint(rep) ? double_reg_allocator_ : general_reg_allocator_;
3160 }
3161 
IsFixedRegisterPolicy(const UnallocatedOperand * operand)3162 bool MidTierRegisterAllocator::IsFixedRegisterPolicy(
3163     const UnallocatedOperand* operand) {
3164   return operand->HasFixedRegisterPolicy() ||
3165          operand->HasFixedFPRegisterPolicy();
3166 }
3167 
ReserveFixedRegisters(int instr_index)3168 void MidTierRegisterAllocator::ReserveFixedRegisters(int instr_index) {
3169   Instruction* instr = code()->InstructionAt(instr_index);
3170   for (size_t i = 0; i < instr->OutputCount(); i++) {
3171     if (!instr->OutputAt(i)->IsUnallocated()) continue;
3172     const UnallocatedOperand* operand =
3173         UnallocatedOperand::cast(instr->OutputAt(i));
3174     if (operand->HasSameAsInputPolicy()) {
3175       DCHECK_EQ(i, 0);
3176       // Input operand has the register constraints, use it here to reserve the
3177       // register for the output (it will be reserved for input below).
3178       operand =
3179           UnallocatedOperand::cast(instr->InputAt(operand->input_index()));
3180     }
3181     if (IsFixedRegisterPolicy(operand)) {
3182       VirtualRegisterData& vreg_data =
3183           VirtualRegisterDataFor(operand->virtual_register());
3184       AllocatorFor(vreg_data.rep())
3185           .ReserveFixedOutputRegister(operand, vreg_data.vreg(),
3186                                       vreg_data.rep(), instr_index);
3187     }
3188   }
3189   for (size_t i = 0; i < instr->TempCount(); i++) {
3190     if (!instr->TempAt(i)->IsUnallocated()) continue;
3191     const UnallocatedOperand* operand =
3192         UnallocatedOperand::cast(instr->TempAt(i));
3193     if (IsFixedRegisterPolicy(operand)) {
3194       int virtual_register = operand->virtual_register();
3195       MachineRepresentation rep =
3196           virtual_register == InstructionOperand::kInvalidVirtualRegister
3197               ? InstructionSequence::DefaultRepresentation()
3198               : code()->GetRepresentation(virtual_register);
3199       AllocatorFor(rep).ReserveFixedTempRegister(operand, virtual_register, rep,
3200                                                  instr_index);
3201     }
3202   }
3203   for (size_t i = 0; i < instr->InputCount(); i++) {
3204     if (!instr->InputAt(i)->IsUnallocated()) continue;
3205     const UnallocatedOperand* operand =
3206         UnallocatedOperand::cast(instr->InputAt(i));
3207     if (IsFixedRegisterPolicy(operand)) {
3208       VirtualRegisterData& vreg_data =
3209           VirtualRegisterDataFor(operand->virtual_register());
3210       AllocatorFor(vreg_data.rep())
3211           .ReserveFixedInputRegister(operand, vreg_data.vreg(), vreg_data.rep(),
3212                                      instr_index);
3213     }
3214   }
3215 }
3216 
AllocatePhiGapMoves(const InstructionBlock * block)3217 void MidTierRegisterAllocator::AllocatePhiGapMoves(
3218     const InstructionBlock* block) {
3219   int successors_phi_index =
3220       data_->block_state(block->rpo_number()).successors_phi_index();
3221 
3222   // If successors_phi_index is -1 there are no phi's in the successor.
3223   if (successors_phi_index == -1) return;
3224 
3225   // The last instruction of a block with phis can't require reference maps
3226   // since we won't record phi gap moves that get spilled when populating the
3227   // reference maps
3228   int instr_index = block->last_instruction_index();
3229   DCHECK(!code()->InstructionAt(instr_index)->HasReferenceMap());
3230 
3231   // If there are phis, we only have a single successor due to edge-split form.
3232   DCHECK_EQ(block->SuccessorCount(), 1);
3233   const InstructionBlock* successor = data_->GetBlock(block->successors()[0]);
3234 
3235   for (PhiInstruction* phi : successor->phis()) {
3236     VirtualRegisterData& to_vreg =
3237         VirtualRegisterDataFor(phi->virtual_register());
3238     VirtualRegisterData& from_vreg =
3239         VirtualRegisterDataFor(phi->operands()[successors_phi_index]);
3240 
3241     AllocatorFor(to_vreg.rep())
3242         .AllocatePhiGapMove(to_vreg, from_vreg, instr_index);
3243   }
3244 }
3245 
AllocatePhis(const InstructionBlock * block)3246 void MidTierRegisterAllocator::AllocatePhis(const InstructionBlock* block) {
3247   for (PhiInstruction* phi : block->phis()) {
3248     VirtualRegisterData& virtual_register =
3249         VirtualRegisterDataFor(phi->virtual_register());
3250     AllocatorFor(virtual_register.rep()).AllocatePhi(virtual_register, block);
3251   }
3252 }
3253 
UpdateSpillRangesForLoops()3254 void MidTierRegisterAllocator::UpdateSpillRangesForLoops() {
3255   // Extend the spill range of any spill that crosses a loop header to
3256   // the full loop.
3257   for (InstructionBlock* block : code()->instruction_blocks()) {
3258     if (block->IsLoopHeader()) {
3259       RpoNumber last_loop_block =
3260           RpoNumber::FromInt(block->loop_end().ToInt() - 1);
3261       int last_loop_instr =
3262           data_->GetBlock(last_loop_block)->last_instruction_index();
3263       // Extend spill range for all spilled values that are live on entry to the
3264       // loop header.
3265       for (int vreg : data_->spilled_virtual_registers()) {
3266         const VirtualRegisterData& vreg_data = VirtualRegisterDataFor(vreg);
3267         if (vreg_data.HasSpillRange() &&
3268             vreg_data.spill_range()->IsLiveAt(block->first_instruction_index(),
3269                                               block)) {
3270           vreg_data.spill_range()->ExtendRangeTo(last_loop_instr);
3271         }
3272       }
3273     }
3274   }
3275 }
3276 
AllocateRegisters(MidTierRegisterAllocationData * data)3277 void AllocateRegisters(MidTierRegisterAllocationData* data) {
3278   MidTierRegisterAllocator allocator(data);
3279   for (InstructionBlock* block :
3280        base::Reversed(data->code()->instruction_blocks())) {
3281     data->tick_counter()->TickAndMaybeEnterSafepoint();
3282     allocator.AllocateRegisters(block);
3283   }
3284 
3285   allocator.UpdateSpillRangesForLoops();
3286 
3287   data->frame()->SetAllocatedRegisters(
3288       allocator.general_reg_allocator().assigned_registers());
3289   data->frame()->SetAllocatedDoubleRegisters(
3290       allocator.double_reg_allocator().assigned_registers());
3291 }
3292 
3293 // Spill slot allocator for mid-tier register allocation.
3294 class MidTierSpillSlotAllocator final {
3295  public:
3296   explicit MidTierSpillSlotAllocator(MidTierRegisterAllocationData* data);
3297   MidTierSpillSlotAllocator(const MidTierSpillSlotAllocator&) = delete;
3298   MidTierSpillSlotAllocator& operator=(const MidTierSpillSlotAllocator&) =
3299       delete;
3300 
3301   void Allocate(VirtualRegisterData* virtual_register);
3302 
3303  private:
3304   class SpillSlot;
3305 
3306   void AdvanceTo(int instr_index);
3307   SpillSlot* GetFreeSpillSlot(int byte_width);
3308 
code() const3309   InstructionSequence* code() const { return data_->code(); }
frame() const3310   Frame* frame() const { return data_->frame(); }
zone() const3311   Zone* zone() const { return data_->allocation_zone(); }
3312 
3313   struct OrderByLastUse {
3314     bool operator()(const SpillSlot* a, const SpillSlot* b) const;
3315   };
3316 
3317   MidTierRegisterAllocationData* const data_;
3318   ZonePriorityQueue<SpillSlot*, OrderByLastUse> allocated_slots_;
3319   ZoneLinkedList<SpillSlot*> free_slots_;
3320   int position_;
3321 };
3322 
3323 class MidTierSpillSlotAllocator::SpillSlot : public ZoneObject {
3324  public:
SpillSlot(int stack_slot,int byte_width)3325   SpillSlot(int stack_slot, int byte_width)
3326       : stack_slot_(stack_slot), byte_width_(byte_width), range_() {}
3327   SpillSlot(const SpillSlot&) = delete;
3328   SpillSlot& operator=(const SpillSlot&) = delete;
3329 
AddRange(const Range & range)3330   void AddRange(const Range& range) { range_.AddRange(range); }
3331 
ToOperand(MachineRepresentation rep) const3332   AllocatedOperand ToOperand(MachineRepresentation rep) const {
3333     return AllocatedOperand(AllocatedOperand::STACK_SLOT, rep, stack_slot_);
3334   }
3335 
byte_width() const3336   int byte_width() const { return byte_width_; }
last_use() const3337   int last_use() const { return range_.end(); }
3338 
3339  private:
3340   int stack_slot_;
3341   int byte_width_;
3342   Range range_;
3343 };
3344 
operator ()(const SpillSlot * a,const SpillSlot * b) const3345 bool MidTierSpillSlotAllocator::OrderByLastUse::operator()(
3346     const SpillSlot* a, const SpillSlot* b) const {
3347   return a->last_use() > b->last_use();
3348 }
3349 
MidTierSpillSlotAllocator(MidTierRegisterAllocationData * data)3350 MidTierSpillSlotAllocator::MidTierSpillSlotAllocator(
3351     MidTierRegisterAllocationData* data)
3352     : data_(data),
3353       allocated_slots_(data->allocation_zone()),
3354       free_slots_(data->allocation_zone()),
3355       position_(0) {}
3356 
AdvanceTo(int instr_index)3357 void MidTierSpillSlotAllocator::AdvanceTo(int instr_index) {
3358   // Move any slots that are no longer in use to the free slots list.
3359   DCHECK_LE(position_, instr_index);
3360   while (!allocated_slots_.empty() &&
3361          instr_index > allocated_slots_.top()->last_use()) {
3362     free_slots_.push_front(allocated_slots_.top());
3363     allocated_slots_.pop();
3364   }
3365   position_ = instr_index;
3366 }
3367 
3368 MidTierSpillSlotAllocator::SpillSlot*
GetFreeSpillSlot(int byte_width)3369 MidTierSpillSlotAllocator::GetFreeSpillSlot(int byte_width) {
3370   for (auto it = free_slots_.begin(); it != free_slots_.end(); ++it) {
3371     SpillSlot* slot = *it;
3372     if (slot->byte_width() == byte_width) {
3373       free_slots_.erase(it);
3374       return slot;
3375     }
3376   }
3377   return nullptr;
3378 }
3379 
Allocate(VirtualRegisterData * virtual_register)3380 void MidTierSpillSlotAllocator::Allocate(
3381     VirtualRegisterData* virtual_register) {
3382   DCHECK(virtual_register->HasPendingSpillOperand());
3383   VirtualRegisterData::SpillRange* spill_range =
3384       virtual_register->spill_range();
3385   MachineRepresentation rep = virtual_register->rep();
3386   int byte_width = ByteWidthForStackSlot(rep);
3387   Range live_range = spill_range->live_range();
3388 
3389   AdvanceTo(live_range.start());
3390 
3391   // Try to re-use an existing free spill slot.
3392   SpillSlot* slot = GetFreeSpillSlot(byte_width);
3393   if (slot == nullptr) {
3394     // Otherwise allocate a new slot.
3395     int stack_slot_ = frame()->AllocateSpillSlot(byte_width);
3396     slot = zone()->New<SpillSlot>(stack_slot_, byte_width);
3397   }
3398 
3399   // Extend the range of the slot to include this spill range, and allocate the
3400   // pending spill operands with this slot.
3401   slot->AddRange(live_range);
3402   virtual_register->AllocatePendingSpillOperand(slot->ToOperand(rep));
3403   allocated_slots_.push(slot);
3404 }
3405 
AllocateSpillSlots(MidTierRegisterAllocationData * data)3406 void AllocateSpillSlots(MidTierRegisterAllocationData* data) {
3407   ZoneVector<VirtualRegisterData*> spilled(data->allocation_zone());
3408   for (int vreg : data->spilled_virtual_registers()) {
3409     VirtualRegisterData& vreg_data = data->VirtualRegisterDataFor(vreg);
3410     if (vreg_data.HasPendingSpillOperand()) {
3411       spilled.push_back(&vreg_data);
3412     }
3413   }
3414 
3415   // Sort the spill ranges by order of their first use to enable linear
3416   // allocation of spill slots.
3417   std::sort(spilled.begin(), spilled.end(),
3418             [](const VirtualRegisterData* a, const VirtualRegisterData* b) {
3419               return a->spill_range()->live_range().start() <
3420                      b->spill_range()->live_range().start();
3421             });
3422 
3423   // Allocate a spill slot for each virtual register with a spill range.
3424   MidTierSpillSlotAllocator allocator(data);
3425   for (VirtualRegisterData* spill : spilled) {
3426     allocator.Allocate(spill);
3427   }
3428 }
3429 
3430 // Populates reference maps for mid-tier register allocation.
3431 class MidTierReferenceMapPopulator final {
3432  public:
3433   explicit MidTierReferenceMapPopulator(MidTierRegisterAllocationData* data);
3434   MidTierReferenceMapPopulator(const MidTierReferenceMapPopulator&) = delete;
3435   MidTierReferenceMapPopulator& operator=(const MidTierReferenceMapPopulator&) =
3436       delete;
3437 
3438   void RecordReferences(const VirtualRegisterData& virtual_register);
3439 
3440  private:
code() const3441   InstructionSequence* code() const { return data_->code(); }
3442 
3443   MidTierRegisterAllocationData* const data_;
3444 };
3445 
MidTierReferenceMapPopulator(MidTierRegisterAllocationData * data)3446 MidTierReferenceMapPopulator::MidTierReferenceMapPopulator(
3447     MidTierRegisterAllocationData* data)
3448     : data_(data) {}
3449 
RecordReferences(const VirtualRegisterData & virtual_register)3450 void MidTierReferenceMapPopulator::RecordReferences(
3451     const VirtualRegisterData& virtual_register) {
3452   if (!virtual_register.HasAllocatedSpillOperand()) return;
3453   if (!code()->IsReference(virtual_register.vreg())) return;
3454 
3455   VirtualRegisterData::SpillRange* spill_range = virtual_register.spill_range();
3456   Range& live_range = spill_range->live_range();
3457   AllocatedOperand allocated =
3458       *AllocatedOperand::cast(virtual_register.spill_operand());
3459   for (int instr_index : data_->reference_map_instructions()) {
3460     if (instr_index > live_range.end() || instr_index < live_range.start())
3461       continue;
3462     Instruction* instr = data_->code()->InstructionAt(instr_index);
3463     DCHECK(instr->HasReferenceMap());
3464 
3465     if (spill_range->IsLiveAt(instr_index, instr->block())) {
3466       instr->reference_map()->RecordReference(allocated);
3467     }
3468   }
3469 }
3470 
PopulateReferenceMaps(MidTierRegisterAllocationData * data)3471 void PopulateReferenceMaps(MidTierRegisterAllocationData* data) {
3472   MidTierReferenceMapPopulator populator(data);
3473   for (int vreg : data->spilled_virtual_registers()) {
3474     populator.RecordReferences(data->VirtualRegisterDataFor(vreg));
3475   }
3476 }
3477 
3478 }  // namespace compiler
3479 }  // namespace internal
3480 }  // namespace v8
3481