V8 Project
lithium-gap-resolver-arm64.cc
Go to the documentation of this file.
1 // Copyright 2013 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/v8.h"
6 
10 
11 namespace v8 {
12 namespace internal {
13 
14 #define __ ACCESS_MASM((&masm_))
15 
16 
18  DelayedMasm::EndDelayedUse();
19  if (scratch_register_used()) {
20  DCHECK(ScratchRegister().Is(root));
21  DCHECK(!pending());
22  InitializeRootRegister();
23  reset_scratch_register_used();
24  }
25 }
26 
27 
28 LGapResolver::LGapResolver(LCodeGen* owner)
29  : cgen_(owner), masm_(owner, owner->masm()), moves_(32, owner->zone()),
30  root_index_(0), in_cycle_(false), saved_destination_(NULL) {
31 }
32 
33 
34 void LGapResolver::Resolve(LParallelMove* parallel_move) {
35  DCHECK(moves_.is_empty());
36  DCHECK(!masm_.pending());
37 
38  // Build up a worklist of moves.
39  BuildInitialMoveList(parallel_move);
40 
41  for (int i = 0; i < moves_.length(); ++i) {
42  LMoveOperands move = moves_[i];
43 
44  // Skip constants to perform them last. They don't block other moves
45  // and skipping such moves with register destinations keeps those
46  // registers free for the whole algorithm.
47  if (!move.IsEliminated() && !move.source()->IsConstantOperand()) {
48  root_index_ = i; // Any cycle is found when we reach this move again.
49  PerformMove(i);
50  if (in_cycle_) RestoreValue();
51  }
52  }
53 
54  // Perform the moves with constant sources.
55  for (int i = 0; i < moves_.length(); ++i) {
56  LMoveOperands move = moves_[i];
57 
58  if (!move.IsEliminated()) {
59  DCHECK(move.source()->IsConstantOperand());
60  EmitMove(i);
61  }
62  }
63 
64  __ EndDelayedUse();
65 
66  moves_.Rewind(0);
67 }
68 
69 
70 void LGapResolver::BuildInitialMoveList(LParallelMove* parallel_move) {
71  // Perform a linear sweep of the moves to add them to the initial list of
72  // moves to perform, ignoring any move that is redundant (the source is
73  // the same as the destination, the destination is ignored and
74  // unallocated, or the move was already eliminated).
75  const ZoneList<LMoveOperands>* moves = parallel_move->move_operands();
76  for (int i = 0; i < moves->length(); ++i) {
77  LMoveOperands move = moves->at(i);
78  if (!move.IsRedundant()) moves_.Add(move, cgen_->zone());
79  }
80  Verify();
81 }
82 
83 
84 void LGapResolver::PerformMove(int index) {
85  // Each call to this function performs a move and deletes it from the move
86  // graph. We first recursively perform any move blocking this one. We
87  // mark a move as "pending" on entry to PerformMove in order to detect
88  // cycles in the move graph.
89  LMoveOperands& current_move = moves_[index];
90 
91  DCHECK(!current_move.IsPending());
92  DCHECK(!current_move.IsRedundant());
93 
94  // Clear this move's destination to indicate a pending move. The actual
95  // destination is saved in a stack allocated local. Multiple moves can
96  // be pending because this function is recursive.
97  DCHECK(current_move.source() != NULL); // Otherwise it will look eliminated.
98  LOperand* destination = current_move.destination();
99  current_move.set_destination(NULL);
100 
101  // Perform a depth-first traversal of the move graph to resolve
102  // dependencies. Any unperformed, unpending move with a source the same
103  // as this one's destination blocks this one so recursively perform all
104  // such moves.
105  for (int i = 0; i < moves_.length(); ++i) {
106  LMoveOperands other_move = moves_[i];
107  if (other_move.Blocks(destination) && !other_move.IsPending()) {
108  PerformMove(i);
109  // If there is a blocking, pending move it must be moves_[root_index_]
110  // and all other moves with the same source as moves_[root_index_] are
111  // sucessfully executed (because they are cycle-free) by this loop.
112  }
113  }
114 
115  // We are about to resolve this move and don't need it marked as
116  // pending, so restore its destination.
117  current_move.set_destination(destination);
118 
119  // The move may be blocked on a pending move, which must be the starting move.
120  // In this case, we have a cycle, and we save the source of this move to
121  // a scratch register to break it.
122  LMoveOperands other_move = moves_[root_index_];
123  if (other_move.Blocks(destination)) {
124  DCHECK(other_move.IsPending());
125  BreakCycle(index);
126  return;
127  }
128 
129  // This move is no longer blocked.
130  EmitMove(index);
131 }
132 
133 
134 void LGapResolver::Verify() {
135 #ifdef ENABLE_SLOW_DCHECKS
136  // No operand should be the destination for more than one move.
137  for (int i = 0; i < moves_.length(); ++i) {
138  LOperand* destination = moves_[i].destination();
139  for (int j = i + 1; j < moves_.length(); ++j) {
140  SLOW_DCHECK(!destination->Equals(moves_[j].destination()));
141  }
142  }
143 #endif
144 }
145 
146 
147 void LGapResolver::BreakCycle(int index) {
148  DCHECK(moves_[index].destination()->Equals(moves_[root_index_].source()));
149  DCHECK(!in_cycle_);
150 
151  // We save in a register the source of that move and we remember its
152  // destination. Then we mark this move as resolved so the cycle is
153  // broken and we can perform the other moves.
154  in_cycle_ = true;
155  LOperand* source = moves_[index].source();
156  saved_destination_ = moves_[index].destination();
157 
158  if (source->IsRegister()) {
159  AcquireSavedValueRegister();
160  __ Mov(SavedValueRegister(), cgen_->ToRegister(source));
161  } else if (source->IsStackSlot()) {
162  AcquireSavedValueRegister();
163  __ Load(SavedValueRegister(), cgen_->ToMemOperand(source));
164  } else if (source->IsDoubleRegister()) {
165  __ Fmov(SavedFPValueRegister(), cgen_->ToDoubleRegister(source));
166  } else if (source->IsDoubleStackSlot()) {
167  __ Load(SavedFPValueRegister(), cgen_->ToMemOperand(source));
168  } else {
169  UNREACHABLE();
170  }
171 
172  // Mark this move as resolved.
173  // This move will be actually performed by moving the saved value to this
174  // move's destination in LGapResolver::RestoreValue().
175  moves_[index].Eliminate();
176 }
177 
178 
179 void LGapResolver::RestoreValue() {
180  DCHECK(in_cycle_);
181  DCHECK(saved_destination_ != NULL);
182 
183  if (saved_destination_->IsRegister()) {
184  __ Mov(cgen_->ToRegister(saved_destination_), SavedValueRegister());
185  ReleaseSavedValueRegister();
186  } else if (saved_destination_->IsStackSlot()) {
187  __ Store(SavedValueRegister(), cgen_->ToMemOperand(saved_destination_));
188  ReleaseSavedValueRegister();
189  } else if (saved_destination_->IsDoubleRegister()) {
190  __ Fmov(cgen_->ToDoubleRegister(saved_destination_),
191  SavedFPValueRegister());
192  } else if (saved_destination_->IsDoubleStackSlot()) {
193  __ Store(SavedFPValueRegister(), cgen_->ToMemOperand(saved_destination_));
194  } else {
195  UNREACHABLE();
196  }
197 
198  in_cycle_ = false;
199  saved_destination_ = NULL;
200 }
201 
202 
203 void LGapResolver::EmitMove(int index) {
204  LOperand* source = moves_[index].source();
205  LOperand* destination = moves_[index].destination();
206 
207  // Dispatch on the source and destination operand kinds. Not all
208  // combinations are possible.
209 
210  if (source->IsRegister()) {
211  Register source_register = cgen_->ToRegister(source);
212  if (destination->IsRegister()) {
213  __ Mov(cgen_->ToRegister(destination), source_register);
214  } else {
215  DCHECK(destination->IsStackSlot());
216  __ Store(source_register, cgen_->ToMemOperand(destination));
217  }
218 
219  } else if (source->IsStackSlot()) {
220  MemOperand source_operand = cgen_->ToMemOperand(source);
221  if (destination->IsRegister()) {
222  __ Load(cgen_->ToRegister(destination), source_operand);
223  } else {
224  DCHECK(destination->IsStackSlot());
225  EmitStackSlotMove(index);
226  }
227 
228  } else if (source->IsConstantOperand()) {
229  LConstantOperand* constant_source = LConstantOperand::cast(source);
230  if (destination->IsRegister()) {
231  Register dst = cgen_->ToRegister(destination);
232  if (cgen_->IsSmi(constant_source)) {
233  __ Mov(dst, cgen_->ToSmi(constant_source));
234  } else if (cgen_->IsInteger32Constant(constant_source)) {
235  __ Mov(dst, cgen_->ToInteger32(constant_source));
236  } else {
237  __ LoadObject(dst, cgen_->ToHandle(constant_source));
238  }
239  } else if (destination->IsDoubleRegister()) {
240  DoubleRegister result = cgen_->ToDoubleRegister(destination);
241  __ Fmov(result, cgen_->ToDouble(constant_source));
242  } else {
243  DCHECK(destination->IsStackSlot());
244  DCHECK(!in_cycle_); // Constant moves happen after all cycles are gone.
245  if (cgen_->IsSmi(constant_source)) {
246  Smi* smi = cgen_->ToSmi(constant_source);
247  __ StoreConstant(reinterpret_cast<intptr_t>(smi),
248  cgen_->ToMemOperand(destination));
249  } else if (cgen_->IsInteger32Constant(constant_source)) {
250  __ StoreConstant(cgen_->ToInteger32(constant_source),
251  cgen_->ToMemOperand(destination));
252  } else {
253  Handle<Object> handle = cgen_->ToHandle(constant_source);
254  AllowDeferredHandleDereference smi_object_check;
255  if (handle->IsSmi()) {
256  Object* obj = *handle;
257  DCHECK(!obj->IsHeapObject());
258  __ StoreConstant(reinterpret_cast<intptr_t>(obj),
259  cgen_->ToMemOperand(destination));
260  } else {
261  AcquireSavedValueRegister();
262  __ LoadObject(SavedValueRegister(), handle);
263  __ Store(SavedValueRegister(), cgen_->ToMemOperand(destination));
264  ReleaseSavedValueRegister();
265  }
266  }
267  }
268 
269  } else if (source->IsDoubleRegister()) {
270  DoubleRegister src = cgen_->ToDoubleRegister(source);
271  if (destination->IsDoubleRegister()) {
272  __ Fmov(cgen_->ToDoubleRegister(destination), src);
273  } else {
274  DCHECK(destination->IsDoubleStackSlot());
275  __ Store(src, cgen_->ToMemOperand(destination));
276  }
277 
278  } else if (source->IsDoubleStackSlot()) {
279  MemOperand src = cgen_->ToMemOperand(source);
280  if (destination->IsDoubleRegister()) {
281  __ Load(cgen_->ToDoubleRegister(destination), src);
282  } else {
283  DCHECK(destination->IsDoubleStackSlot());
284  EmitStackSlotMove(index);
285  }
286 
287  } else {
288  UNREACHABLE();
289  }
290 
291  // The move has been emitted, we can eliminate it.
292  moves_[index].Eliminate();
293 }
294 
295 } } // namespace v8::internal
#define SLOW_DCHECK(condition)
Definition: checks.h:30
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define UNREACHABLE()
Definition: logging.h:30
#define DCHECK(condition)
Definition: logging.h:205
bool Is(Object *obj)
DwVfpRegister DoubleRegister
kSerializedDataOffset Object
Definition: objects-inl.h:5322
Handle< T > handle(T *t, Isolate *isolate)
Definition: handles.h:146
PerThreadAssertScopeDebugOnly< DEFERRED_HANDLE_DEREFERENCE_ASSERT, true > AllowDeferredHandleDereference
Definition: assert-scope.h:130
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20