LCOV - code coverage report
Current view: top level - js/src/jit - MoveResolver.h (source / functions) Hit Total Coverage
Test: output.info Lines: 110 134 82.1 %
Date: 2017-07-14 16:53:18 Functions: 36 40 90.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef jit_MoveResolver_h
       8             : #define jit_MoveResolver_h
       9             : 
      10             : #include "jit/InlineList.h"
      11             : #include "jit/JitAllocPolicy.h"
      12             : #include "jit/Registers.h"
      13             : #include "jit/RegisterSets.h"
      14             : 
      15             : namespace js {
      16             : namespace jit {
      17             : 
      18             : class MacroAssembler;
      19             : 
      20             : // This is similar to Operand, but carries more information. We're also not
      21             : // guaranteed that Operand looks like this on all ISAs.
      22             : class MoveOperand
      23             : {
      24             :   public:
      25             :     enum Kind {
      26             :         // A register in the "integer", aka "general purpose", class.
      27             :         REG,
      28             : #ifdef JS_CODEGEN_REGISTER_PAIR
      29             :         // Two consecutive "integer" register (aka "general purpose"). The even
      30             :         // register contains the lower part, the odd register has the high bits
      31             :         // of the content.
      32             :         REG_PAIR,
      33             : #endif
      34             :         // A register in the "float" register class.
      35             :         FLOAT_REG,
      36             :         // A memory region.
      37             :         MEMORY,
      38             :         // The address of a memory region.
      39             :         EFFECTIVE_ADDRESS
      40             :     };
      41             : 
      42             :   private:
      43             :     Kind kind_;
      44             :     uint32_t code_;
      45             :     int32_t disp_;
      46             : 
      47             :   public:
      48       12146 :     MoveOperand()
      49       12146 :     { }
      50       17926 :     explicit MoveOperand(Register reg) : kind_(REG), code_(reg.code())
      51       17926 :     { }
      52           1 :     explicit MoveOperand(FloatRegister reg) : kind_(FLOAT_REG), code_(reg.code())
      53           1 :     { }
      54        2858 :     MoveOperand(Register reg, int32_t disp, Kind kind = MEMORY)
      55        2858 :         : kind_(kind),
      56        2858 :         code_(reg.code()),
      57        5716 :         disp_(disp)
      58             :     {
      59        2858 :         MOZ_ASSERT(isMemoryOrEffectiveAddress());
      60             : 
      61             :         // With a zero offset, this is a plain reg-to-reg move.
      62        2858 :         if (disp == 0 && kind_ == EFFECTIVE_ADDRESS)
      63         672 :             kind_ = REG;
      64        2858 :     }
      65             :     MoveOperand(MacroAssembler& masm, const ABIArg& arg);
      66      108618 :     MoveOperand(const MoveOperand& other)
      67      108618 :       : kind_(other.kind_),
      68      108618 :         code_(other.code_),
      69      217236 :         disp_(other.disp_)
      70      108618 :     { }
      71          34 :     bool isFloatReg() const {
      72          34 :         return kind_ == FLOAT_REG;
      73             :     }
      74       90555 :     bool isGeneralReg() const {
      75       90555 :         return kind_ == REG;
      76             :     }
      77       64170 :     bool isGeneralRegPair() const {
      78             : #ifdef JS_CODEGEN_REGISTER_PAIR
      79             :         return kind_ == REG_PAIR;
      80             : #else
      81       64170 :         return false;
      82             : #endif
      83             :     }
      84      123837 :     bool isMemory() const {
      85      123837 :         return kind_ == MEMORY;
      86             :     }
      87       83204 :     bool isEffectiveAddress() const {
      88       83204 :         return kind_ == EFFECTIVE_ADDRESS;
      89             :     }
      90      102823 :     bool isMemoryOrEffectiveAddress() const {
      91      102823 :         return isMemory() || isEffectiveAddress();
      92             :     }
      93       43186 :     Register reg() const {
      94       43186 :         MOZ_ASSERT(isGeneralReg());
      95       43186 :         return Register::FromCode(code_);
      96             :     }
      97           0 :     Register evenReg() const {
      98           0 :         MOZ_ASSERT(isGeneralRegPair());
      99           0 :         return Register::FromCode(code_);
     100             :     }
     101           0 :     Register oddReg() const {
     102           0 :         MOZ_ASSERT(isGeneralRegPair());
     103           0 :         return Register::FromCode(code_ + 1);
     104             :     }
     105           8 :     FloatRegister floatReg() const {
     106           8 :         MOZ_ASSERT(isFloatReg());
     107           8 :         return FloatRegister::FromCode(code_);
     108             :     }
     109       10980 :     Register base() const {
     110       10980 :         MOZ_ASSERT(isMemoryOrEffectiveAddress());
     111       10980 :         return Register::FromCode(code_);
     112             :     }
     113        2760 :     int32_t disp() const {
     114        2760 :         MOZ_ASSERT(isMemoryOrEffectiveAddress());
     115        2760 :         return disp_;
     116             :     }
     117             : 
     118       32085 :     bool aliases(MoveOperand other) const {
     119             : 
     120             :         // These are not handled presently, but MEMORY and EFFECTIVE_ADDRESS
     121             :         // only appear in controlled circumstances in the trampoline code
     122             :         // which ensures these cases never come up.
     123             : 
     124       32085 :         MOZ_ASSERT_IF(isMemoryOrEffectiveAddress() && other.isGeneralReg(),
     125             :                       base() != other.reg());
     126       32085 :         MOZ_ASSERT_IF(other.isMemoryOrEffectiveAddress() && isGeneralReg(),
     127             :                       other.base() != reg());
     128             : 
     129             :         // Check if one of the operand is a registe rpair, in which case, we
     130             :         // have to check any other register, or register pair.
     131       32085 :         if (isGeneralRegPair() || other.isGeneralRegPair()) {
     132           0 :             if (isGeneralRegPair() && other.isGeneralRegPair()) {
     133             :                 // Assume that register pairs are aligned on even registers.
     134           0 :                 MOZ_ASSERT(!evenReg().aliases(other.oddReg()));
     135           0 :                 MOZ_ASSERT(!oddReg().aliases(other.evenReg()));
     136             :                 // Pair of registers are composed of consecutive registers, thus
     137             :                 // if the first registers are aliased, then the second registers
     138             :                 // are aliased too.
     139           0 :                 MOZ_ASSERT(evenReg().aliases(other.evenReg()) == oddReg().aliases(other.oddReg()));
     140           0 :                 return evenReg().aliases(other.evenReg());
     141           0 :             } else if (other.isGeneralReg()) {
     142           0 :                 MOZ_ASSERT(isGeneralRegPair());
     143           0 :                 return evenReg().aliases(other.reg()) ||
     144           0 :                        oddReg().aliases(other.reg());
     145           0 :             } else if (isGeneralReg()) {
     146           0 :                 MOZ_ASSERT(other.isGeneralRegPair());
     147           0 :                 return other.evenReg().aliases(reg()) ||
     148           0 :                        other.oddReg().aliases(reg());
     149             :             }
     150           0 :             return false;
     151             :         }
     152             : 
     153       32085 :         if (kind_ != other.kind_)
     154        7690 :             return false;
     155       24395 :         if (kind_ == FLOAT_REG)
     156           0 :             return floatReg().aliases(other.floatReg());
     157       24395 :         if (code_ != other.code_)
     158       23764 :             return false;
     159         631 :         if (isMemoryOrEffectiveAddress())
     160         516 :             return disp_ == other.disp_;
     161         115 :         return true;
     162             :     }
     163             : 
     164       40170 :     bool operator ==(const MoveOperand& other) const {
     165       40170 :         if (kind_ != other.kind_)
     166        4759 :             return false;
     167       35411 :         if (code_ != other.code_)
     168       33860 :             return false;
     169        1551 :         if (isMemoryOrEffectiveAddress())
     170         446 :             return disp_ == other.disp_;
     171        1105 :         return true;
     172             :     }
     173          10 :     bool operator !=(const MoveOperand& other) const {
     174          10 :         return !operator==(other);
     175             :     }
     176             : };
     177             : 
     178             : // This represents a move operation.
     179       19134 : class MoveOp
     180             : {
     181             :   protected:
     182             :     MoveOperand from_;
     183             :     MoveOperand to_;
     184             :     bool cycleBegin_;
     185             :     bool cycleEnd_;
     186             :     int cycleBeginSlot_;
     187             :     int cycleEndSlot_;
     188             :   public:
     189             :     enum Type {
     190             :         GENERAL,
     191             :         INT32,
     192             :         FLOAT32,
     193             :         DOUBLE,
     194             :         SIMD128INT,
     195             :         SIMD128FLOAT
     196             :     };
     197             : 
     198             :   protected:
     199             :     Type type_;
     200             : 
     201             :     // If cycleBegin_ is true, endCycleType_ is the type of the move at the end
     202             :     // of the cycle. For example, given these moves:
     203             :     //       INT32 move a -> b
     204             :     //     GENERAL move b -> a
     205             :     // the move resolver starts by copying b into a temporary location, so that
     206             :     // the last move can read it. This copy needs to use use type GENERAL.
     207             :     Type endCycleType_;
     208             : 
     209             :   public:
     210        4915 :     MoveOp()
     211        4915 :     { }
     212       19133 :     MoveOp(const MoveOperand& from, const MoveOperand& to, Type type)
     213       19133 :       : from_(from),
     214             :         to_(to),
     215             :         cycleBegin_(false),
     216             :         cycleEnd_(false),
     217             :         cycleBeginSlot_(-1),
     218             :         cycleEndSlot_(-1),
     219       19133 :         type_(type)
     220       19133 :     { }
     221             : 
     222       20213 :     bool isCycleBegin() const {
     223       20213 :         return cycleBegin_;
     224             :     }
     225       20218 :     bool isCycleEnd() const {
     226       20218 :         return cycleEnd_;
     227             :     }
     228             :     uint32_t cycleBeginSlot() const {
     229             :         MOZ_ASSERT(cycleBeginSlot_ != -1);
     230             :         return cycleBeginSlot_;
     231             :     }
     232             :     uint32_t cycleEndSlot() const {
     233             :         MOZ_ASSERT(cycleEndSlot_ != -1);
     234             :         return cycleEndSlot_;
     235             :     }
     236       71724 :     const MoveOperand& from() const {
     237       71724 :         return from_;
     238             :     }
     239       49901 :     const MoveOperand& to() const {
     240       49901 :         return to_;
     241             :     }
     242       19129 :     Type type() const {
     243       19129 :         return type_;
     244             :     }
     245           0 :     Type endCycleType() const {
     246           0 :         MOZ_ASSERT(isCycleBegin());
     247           0 :         return endCycleType_;
     248             :     }
     249        2706 :     bool aliases(const MoveOperand& op) const {
     250        2706 :         return from().aliases(op) || to().aliases(op);
     251             :     }
     252        1353 :     bool aliases(const MoveOp& other) const {
     253        1353 :         return aliases(other.from()) || aliases(other.to());
     254             :     }
     255             : #ifdef JS_CODEGEN_ARM
     256             :     void overwrite(MoveOperand& from, MoveOperand& to, Type type) {
     257             :         from_ = from;
     258             :         to_ = to;
     259             :         type_ = type;
     260             :     }
     261             : #endif
     262             : };
     263             : 
     264        4503 : class MoveResolver
     265             : {
     266             :   private:
     267             :     struct PendingMove
     268             :       : public MoveOp,
     269             :         public TempObject,
     270             :         public InlineListNode<PendingMove>
     271             :     {
     272        4915 :         PendingMove()
     273        4915 :         { }
     274       19133 :         PendingMove(const MoveOperand& from, const MoveOperand& to, Type type)
     275       19133 :           : MoveOp(from, to, type)
     276       19133 :         { }
     277             : 
     278           5 :         void setCycleBegin(Type endCycleType, int cycleSlot) {
     279           5 :             MOZ_ASSERT(!cycleBegin_);
     280           5 :             cycleBegin_ = true;
     281           5 :             cycleBeginSlot_ = cycleSlot;
     282           5 :             endCycleType_ = endCycleType;
     283           5 :         }
     284           5 :         void setCycleEnd(int cycleSlot) {
     285           5 :             MOZ_ASSERT(!cycleEnd_);
     286           5 :             cycleEnd_ = true;
     287           5 :             cycleEndSlot_ = cycleSlot;
     288           5 :         }
     289             :     };
     290             : 
     291             :     typedef InlineList<MoveResolver::PendingMove>::iterator PendingMoveIterator;
     292             : 
     293             :     js::Vector<MoveOp, 16, SystemAllocPolicy> orderedMoves_;
     294             :     int numCycles_;
     295             :     int curCycles_;
     296             :     TempObjectPool<PendingMove> movePool_;
     297             : 
     298             :     InlineList<PendingMove> pending_;
     299             : 
     300             :     PendingMove* findBlockingMove(const PendingMove* last);
     301             :     PendingMove* findCycledMove(PendingMoveIterator* stack, PendingMoveIterator end, const PendingMove* first);
     302             :     MOZ_MUST_USE bool addOrderedMove(const MoveOp& move);
     303             :     void reorderMove(size_t from, size_t to);
     304             : 
     305             :     // Internal reset function. Does not clear lists.
     306             :     void resetState();
     307             : 
     308             : #ifdef JS_CODEGEN_ARM
     309             :     bool isDoubleAliasedAsSingle(const MoveOperand& move);
     310             : #endif
     311             : 
     312             :   public:
     313             :     MoveResolver();
     314             : 
     315             :     // Resolves a move group into two lists of ordered moves. These moves must
     316             :     // be executed in the order provided. Some moves may indicate that they
     317             :     // participate in a cycle. For every cycle there are two such moves, and it
     318             :     // is guaranteed that cycles do not nest inside each other in the list.
     319             :     //
     320             :     // After calling addMove() for each parallel move, resolve() performs the
     321             :     // cycle resolution algorithm. Calling addMove() again resets the resolver.
     322             :     MOZ_MUST_USE bool addMove(const MoveOperand& from, const MoveOperand& to, MoveOp::Type type);
     323             :     MOZ_MUST_USE bool resolve();
     324             :     void sortMemoryToMemoryMoves();
     325             : 
     326       32581 :     size_t numMoves() const {
     327       32581 :         return orderedMoves_.length();
     328             :     }
     329       19164 :     const MoveOp& getMove(size_t i) const {
     330       19164 :         return orderedMoves_[i];
     331             :     }
     332             :     uint32_t numCycles() const {
     333             :         return numCycles_;
     334             :     }
     335        4503 :     void setAllocator(TempAllocator& alloc) {
     336        4503 :         movePool_.setAllocator(alloc);
     337        4503 :     }
     338             : };
     339             : 
     340             : } // namespace jit
     341             : } // namespace js
     342             : 
     343             : #endif /* jit_MoveResolver_h */

Generated by: LCOV version 1.13