Home | History | Annotate | Download | only in arm64
      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/crankshaft/arm64/delayed-masm-arm64-inl.h"
      6 #include "src/crankshaft/arm64/lithium-codegen-arm64.h"
      7 #include "src/crankshaft/arm64/lithium-gap-resolver-arm64.h"
      8 
      9 namespace v8 {
     10 namespace internal {
     11 
     12 #define __ ACCESS_MASM((&masm_))
     13 
     14 
     15 void DelayedGapMasm::EndDelayedUse() {
     16   DelayedMasm::EndDelayedUse();
     17   if (scratch_register_used()) {
     18     DCHECK(ScratchRegister().Is(root));
     19     DCHECK(!pending());
     20     InitializeRootRegister();
     21     reset_scratch_register_used();
     22   }
     23 }
     24 
     25 
     26 LGapResolver::LGapResolver(LCodeGen* owner)
     27     : cgen_(owner), masm_(owner, owner->masm()), moves_(32, owner->zone()),
     28       root_index_(0), in_cycle_(false), saved_destination_(NULL) {
     29 }
     30 
     31 
     32 void LGapResolver::Resolve(LParallelMove* parallel_move) {
     33   DCHECK(moves_.is_empty());
     34   DCHECK(!masm_.pending());
     35 
     36   // Build up a worklist of moves.
     37   BuildInitialMoveList(parallel_move);
     38 
     39   for (int i = 0; i < moves_.length(); ++i) {
     40     LMoveOperands move = moves_[i];
     41 
     42     // Skip constants to perform them last. They don't block other moves
     43     // and skipping such moves with register destinations keeps those
     44     // registers free for the whole algorithm.
     45     if (!move.IsEliminated() && !move.source()->IsConstantOperand()) {
     46       root_index_ = i;  // Any cycle is found when we reach this move again.
     47       PerformMove(i);
     48       if (in_cycle_) RestoreValue();
     49     }
     50   }
     51 
     52   // Perform the moves with constant sources.
     53   for (int i = 0; i < moves_.length(); ++i) {
     54     LMoveOperands move = moves_[i];
     55 
     56     if (!move.IsEliminated()) {
     57       DCHECK(move.source()->IsConstantOperand());
     58       EmitMove(i);
     59     }
     60   }
     61 
     62   __ EndDelayedUse();
     63 
     64   moves_.Rewind(0);
     65 }
     66 
     67 
     68 void LGapResolver::BuildInitialMoveList(LParallelMove* parallel_move) {
     69   // Perform a linear sweep of the moves to add them to the initial list of
     70   // moves to perform, ignoring any move that is redundant (the source is
     71   // the same as the destination, the destination is ignored and
     72   // unallocated, or the move was already eliminated).
     73   const ZoneList<LMoveOperands>* moves = parallel_move->move_operands();
     74   for (int i = 0; i < moves->length(); ++i) {
     75     LMoveOperands move = moves->at(i);
     76     if (!move.IsRedundant()) moves_.Add(move, cgen_->zone());
     77   }
     78   Verify();
     79 }
     80 
     81 
     82 void LGapResolver::PerformMove(int index) {
     83   // Each call to this function performs a move and deletes it from the move
     84   // graph. We first recursively perform any move blocking this one. We
     85   // mark a move as "pending" on entry to PerformMove in order to detect
     86   // cycles in the move graph.
     87   LMoveOperands& current_move = moves_[index];
     88 
     89   DCHECK(!current_move.IsPending());
     90   DCHECK(!current_move.IsRedundant());
     91 
     92   // Clear this move's destination to indicate a pending move.  The actual
     93   // destination is saved in a stack allocated local. Multiple moves can
     94   // be pending because this function is recursive.
     95   DCHECK(current_move.source() != NULL);  // Otherwise it will look eliminated.
     96   LOperand* destination = current_move.destination();
     97   current_move.set_destination(NULL);
     98 
     99   // Perform a depth-first traversal of the move graph to resolve
    100   // dependencies. Any unperformed, unpending move with a source the same
    101   // as this one's destination blocks this one so recursively perform all
    102   // such moves.
    103   for (int i = 0; i < moves_.length(); ++i) {
    104     LMoveOperands other_move = moves_[i];
    105     if (other_move.Blocks(destination) && !other_move.IsPending()) {
    106       PerformMove(i);
    107       // If there is a blocking, pending move it must be moves_[root_index_]
    108       // and all other moves with the same source as moves_[root_index_] are
    109       // sucessfully executed (because they are cycle-free) by this loop.
    110     }
    111   }
    112 
    113   // We are about to resolve this move and don't need it marked as
    114   // pending, so restore its destination.
    115   current_move.set_destination(destination);
    116 
    117   // The move may be blocked on a pending move, which must be the starting move.
    118   // In this case, we have a cycle, and we save the source of this move to
    119   // a scratch register to break it.
    120   LMoveOperands other_move = moves_[root_index_];
    121   if (other_move.Blocks(destination)) {
    122     DCHECK(other_move.IsPending());
    123     BreakCycle(index);
    124     return;
    125   }
    126 
    127   // This move is no longer blocked.
    128   EmitMove(index);
    129 }
    130 
    131 
    132 void LGapResolver::Verify() {
    133 #ifdef ENABLE_SLOW_DCHECKS
    134   // No operand should be the destination for more than one move.
    135   for (int i = 0; i < moves_.length(); ++i) {
    136     LOperand* destination = moves_[i].destination();
    137     for (int j = i + 1; j < moves_.length(); ++j) {
    138       SLOW_DCHECK(!destination->Equals(moves_[j].destination()));
    139     }
    140   }
    141 #endif
    142 }
    143 
    144 
    145 void LGapResolver::BreakCycle(int index) {
    146   DCHECK(moves_[index].destination()->Equals(moves_[root_index_].source()));
    147   DCHECK(!in_cycle_);
    148 
    149   // We save in a register the source of that move and we remember its
    150   // destination. Then we mark this move as resolved so the cycle is
    151   // broken and we can perform the other moves.
    152   in_cycle_ = true;
    153   LOperand* source = moves_[index].source();
    154   saved_destination_ = moves_[index].destination();
    155 
    156   if (source->IsRegister()) {
    157     AcquireSavedValueRegister();
    158     __ Mov(SavedValueRegister(), cgen_->ToRegister(source));
    159   } else if (source->IsStackSlot()) {
    160     AcquireSavedValueRegister();
    161     __ Load(SavedValueRegister(), cgen_->ToMemOperand(source));
    162   } else if (source->IsDoubleRegister()) {
    163     __ Fmov(SavedFPValueRegister(), cgen_->ToDoubleRegister(source));
    164   } else if (source->IsDoubleStackSlot()) {
    165     __ Load(SavedFPValueRegister(), cgen_->ToMemOperand(source));
    166   } else {
    167     UNREACHABLE();
    168   }
    169 
    170   // Mark this move as resolved.
    171   // This move will be actually performed by moving the saved value to this
    172   // move's destination in LGapResolver::RestoreValue().
    173   moves_[index].Eliminate();
    174 }
    175 
    176 
    177 void LGapResolver::RestoreValue() {
    178   DCHECK(in_cycle_);
    179   DCHECK(saved_destination_ != NULL);
    180 
    181   if (saved_destination_->IsRegister()) {
    182     __ Mov(cgen_->ToRegister(saved_destination_), SavedValueRegister());
    183     ReleaseSavedValueRegister();
    184   } else if (saved_destination_->IsStackSlot()) {
    185     __ Store(SavedValueRegister(), cgen_->ToMemOperand(saved_destination_));
    186     ReleaseSavedValueRegister();
    187   } else if (saved_destination_->IsDoubleRegister()) {
    188     __ Fmov(cgen_->ToDoubleRegister(saved_destination_),
    189             SavedFPValueRegister());
    190   } else if (saved_destination_->IsDoubleStackSlot()) {
    191     __ Store(SavedFPValueRegister(), cgen_->ToMemOperand(saved_destination_));
    192   } else {
    193     UNREACHABLE();
    194   }
    195 
    196   in_cycle_ = false;
    197   saved_destination_ = NULL;
    198 }
    199 
    200 
    201 void LGapResolver::EmitMove(int index) {
    202   LOperand* source = moves_[index].source();
    203   LOperand* destination = moves_[index].destination();
    204 
    205   // Dispatch on the source and destination operand kinds.  Not all
    206   // combinations are possible.
    207 
    208   if (source->IsRegister()) {
    209     Register source_register = cgen_->ToRegister(source);
    210     if (destination->IsRegister()) {
    211       __ Mov(cgen_->ToRegister(destination), source_register);
    212     } else {
    213       DCHECK(destination->IsStackSlot());
    214       __ Store(source_register, cgen_->ToMemOperand(destination));
    215     }
    216 
    217   } else if (source->IsStackSlot()) {
    218     MemOperand source_operand = cgen_->ToMemOperand(source);
    219     if (destination->IsRegister()) {
    220       __ Load(cgen_->ToRegister(destination), source_operand);
    221     } else {
    222       DCHECK(destination->IsStackSlot());
    223       EmitStackSlotMove(index);
    224     }
    225 
    226   } else if (source->IsConstantOperand()) {
    227     LConstantOperand* constant_source = LConstantOperand::cast(source);
    228     if (destination->IsRegister()) {
    229       Register dst = cgen_->ToRegister(destination);
    230       if (cgen_->IsSmi(constant_source)) {
    231         __ Mov(dst, cgen_->ToSmi(constant_source));
    232       } else if (cgen_->IsInteger32Constant(constant_source)) {
    233         __ Mov(dst, cgen_->ToInteger32(constant_source));
    234       } else {
    235         __ LoadObject(dst, cgen_->ToHandle(constant_source));
    236       }
    237     } else if (destination->IsDoubleRegister()) {
    238       DoubleRegister result = cgen_->ToDoubleRegister(destination);
    239       __ Fmov(result, cgen_->ToDouble(constant_source));
    240     } else {
    241       DCHECK(destination->IsStackSlot());
    242       DCHECK(!in_cycle_);  // Constant moves happen after all cycles are gone.
    243       if (cgen_->IsSmi(constant_source)) {
    244         Smi* smi = cgen_->ToSmi(constant_source);
    245         __ StoreConstant(reinterpret_cast<intptr_t>(smi),
    246                          cgen_->ToMemOperand(destination));
    247       } else if (cgen_->IsInteger32Constant(constant_source)) {
    248         __ StoreConstant(cgen_->ToInteger32(constant_source),
    249                          cgen_->ToMemOperand(destination));
    250       } else {
    251         Handle<Object> handle = cgen_->ToHandle(constant_source);
    252         AllowDeferredHandleDereference smi_object_check;
    253         if (handle->IsSmi()) {
    254           Object* obj = *handle;
    255           DCHECK(!obj->IsHeapObject());
    256           __ StoreConstant(reinterpret_cast<intptr_t>(obj),
    257                            cgen_->ToMemOperand(destination));
    258         } else {
    259           AcquireSavedValueRegister();
    260           __ LoadObject(SavedValueRegister(), handle);
    261           __ Store(SavedValueRegister(), cgen_->ToMemOperand(destination));
    262           ReleaseSavedValueRegister();
    263         }
    264       }
    265     }
    266 
    267   } else if (source->IsDoubleRegister()) {
    268     DoubleRegister src = cgen_->ToDoubleRegister(source);
    269     if (destination->IsDoubleRegister()) {
    270       __ Fmov(cgen_->ToDoubleRegister(destination), src);
    271     } else {
    272       DCHECK(destination->IsDoubleStackSlot());
    273       __ Store(src, cgen_->ToMemOperand(destination));
    274     }
    275 
    276   } else if (source->IsDoubleStackSlot()) {
    277     MemOperand src = cgen_->ToMemOperand(source);
    278     if (destination->IsDoubleRegister()) {
    279       __ Load(cgen_->ToDoubleRegister(destination), src);
    280     } else {
    281       DCHECK(destination->IsDoubleStackSlot());
    282       EmitStackSlotMove(index);
    283     }
    284 
    285   } else {
    286     UNREACHABLE();
    287   }
    288 
    289   // The move has been emitted, we can eliminate it.
    290   moves_[index].Eliminate();
    291 }
    292 
    293 }  // namespace internal
    294 }  // namespace v8
    295