| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
| * vim: set ts=8 sts=4 et sw=4 tw=99: |
| * This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #ifndef jit_MoveResolver_h |
| #define jit_MoveResolver_h |
| |
| #include "Registers.h" |
| #include "InlineList.h" |
| #include "IonAllocPolicy.h" |
| |
| namespace js { |
| namespace jit { |
| |
| class MoveResolver |
| { |
| public: |
| // This is similar to Operand, but carries more information. We're also not |
| // guaranteed that Operand looks like this on all ISAs. |
| class MoveOperand |
| { |
| enum Kind { |
| REG, |
| FLOAT_REG, |
| ADDRESS, |
| FLOAT_ADDRESS, |
| EFFECTIVE_ADDRESS |
| }; |
| |
| Kind kind_; |
| uint32_t code_; |
| int32_t disp_; |
| |
| public: |
| enum AddressKind { |
| MEMORY = ADDRESS, |
| EFFECTIVE = EFFECTIVE_ADDRESS, |
| FLOAT = FLOAT_ADDRESS |
| }; |
| |
| MoveOperand() |
| { } |
| explicit MoveOperand(const Register ®) : kind_(REG), code_(reg.code()) |
| { } |
| explicit MoveOperand(const FloatRegister ®) : kind_(FLOAT_REG), code_(reg.code()) |
| { } |
| MoveOperand(const Register ®, int32_t disp, AddressKind addrKind = MEMORY) |
| : kind_((Kind) addrKind), |
| code_(reg.code()), |
| disp_(disp) |
| { } |
| MoveOperand(const MoveOperand &other) |
| : kind_(other.kind_), |
| code_(other.code_), |
| disp_(other.disp_) |
| { } |
| bool isFloatReg() const { |
| return kind_ == FLOAT_REG; |
| } |
| bool isGeneralReg() const { |
| return kind_ == REG; |
| } |
| bool isDouble() const { |
| return kind_ == FLOAT_REG || kind_ == FLOAT_ADDRESS; |
| } |
| bool isMemory() const { |
| return kind_ == ADDRESS; |
| } |
| bool isFloatAddress() const { |
| return kind_ == FLOAT_ADDRESS; |
| } |
| bool isEffectiveAddress() const { |
| return kind_ == EFFECTIVE_ADDRESS; |
| } |
| #if defined(JS_CPU_MIPS) |
| bool isMemoryOrEffectiveAddress() const { |
| return isMemory() || isEffectiveAddress(); |
| } |
| #endif |
| Register reg() const { |
| JS_ASSERT(isGeneralReg()); |
| return Register::FromCode(code_); |
| } |
| FloatRegister floatReg() const { |
| JS_ASSERT(isFloatReg()); |
| return FloatRegister::FromCode(code_); |
| } |
| Register base() const { |
| JS_ASSERT(isMemory() || isEffectiveAddress() || isFloatAddress()); |
| return Register::FromCode(code_); |
| } |
| int32_t disp() const { |
| return disp_; |
| } |
| |
| bool operator ==(const MoveOperand &other) const { |
| if (kind_ != other.kind_) |
| return false; |
| if (code_ != other.code_) |
| return false; |
| if (isMemory() || isEffectiveAddress()) |
| return disp_ == other.disp_; |
| return true; |
| } |
| }; |
| |
| class Move |
| { |
| protected: |
| MoveOperand from_; |
| MoveOperand to_; |
| bool cycle_; |
| |
| public: |
| enum Kind { |
| GENERAL, |
| DOUBLE |
| }; |
| |
| protected: |
| Kind kind_; |
| |
| public: |
| Move() |
| { } |
| Move(const Move &other) |
| : from_(other.from_), |
| to_(other.to_), |
| cycle_(other.cycle_), |
| kind_(other.kind_) |
| { } |
| Move(const MoveOperand &from, const MoveOperand &to, Kind kind, bool cycle = false) |
| : from_(from), |
| to_(to), |
| cycle_(cycle), |
| kind_(kind) |
| { } |
| |
| bool inCycle() const { |
| return cycle_; |
| } |
| const MoveOperand &from() const { |
| return from_; |
| } |
| const MoveOperand &to() const { |
| return to_; |
| } |
| Kind kind() const { |
| return kind_; |
| } |
| }; |
| |
| private: |
| struct PendingMove |
| : public Move, |
| public TempObject, |
| public InlineListNode<PendingMove> |
| { |
| PendingMove() |
| { } |
| PendingMove(const MoveOperand &from, const MoveOperand &to, Kind kind) |
| : Move(from, to, kind, false) |
| { } |
| |
| void setInCycle() { |
| JS_ASSERT(!inCycle()); |
| cycle_ = true; |
| } |
| |
| }; |
| |
| typedef InlineList<MoveResolver::PendingMove>::iterator PendingMoveIterator; |
| |
| private: |
| // Moves that are definitely unblocked (constants to registers). These are |
| // emitted last. |
| js::Vector<Move, 16, SystemAllocPolicy> orderedMoves_; |
| bool hasCycles_; |
| |
| TempObjectPool<PendingMove> movePool_; |
| |
| InlineList<PendingMove> pending_; |
| |
| PendingMove *findBlockingMove(const PendingMove *last); |
| |
| // Internal reset function. Does not clear lists. |
| void resetState(); |
| |
| public: |
| MoveResolver(); |
| |
| // Resolves a move group into two lists of ordered moves. These moves must |
| // be executed in the order provided. Some moves may indicate that they |
| // participate in a cycle. For every cycle there are two such moves, and it |
| // is guaranteed that cycles do not nest inside each other in the list. |
| // |
| // After calling addMove() for each parallel move, resolve() performs the |
| // cycle resolution algorithm. Calling addMove() again resets the resolver. |
| bool addMove(const MoveOperand &from, const MoveOperand &to, Move::Kind kind); |
| bool resolve(); |
| |
| size_t numMoves() const { |
| return orderedMoves_.length(); |
| } |
| const Move &getMove(size_t i) const { |
| return orderedMoves_[i]; |
| } |
| bool hasCycles() const { |
| return hasCycles_; |
| } |
| void clearTempObjectPool() { |
| movePool_.clear(); |
| } |
| }; |
| |
| } // namespace jit |
| } // namespace js |
| |
| #endif /* jit_MoveResolver_h */ |