1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/MoveResolver.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,242 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef jit_MoveResolver_h 1.11 +#define jit_MoveResolver_h 1.12 + 1.13 +#include "jit/InlineList.h" 1.14 +#include "jit/IonAllocPolicy.h" 1.15 +#include "jit/Registers.h" 1.16 + 1.17 +namespace js { 1.18 +namespace jit { 1.19 + 1.20 +// This is similar to Operand, but carries more information. We're also not 1.21 +// guaranteed that Operand looks like this on all ISAs. 1.22 +class MoveOperand 1.23 +{ 1.24 + public: 1.25 + enum Kind { 1.26 + // A register in the "integer", aka "general purpose", class. 1.27 + REG, 1.28 + // A register in the "float" register class. 1.29 + FLOAT_REG, 1.30 + // A memory region. 1.31 + MEMORY, 1.32 + // The address of a memory region. 1.33 + EFFECTIVE_ADDRESS 1.34 + }; 1.35 + 1.36 + private: 1.37 + Kind kind_; 1.38 + uint32_t code_; 1.39 + int32_t disp_; 1.40 + 1.41 + public: 1.42 + MoveOperand() 1.43 + { } 1.44 + explicit MoveOperand(const Register ®) : kind_(REG), code_(reg.code()) 1.45 + { } 1.46 + explicit MoveOperand(const FloatRegister ®) : kind_(FLOAT_REG), code_(reg.code()) 1.47 + { } 1.48 + MoveOperand(const Register ®, int32_t disp, Kind kind = MEMORY) 1.49 + : kind_(kind), 1.50 + code_(reg.code()), 1.51 + disp_(disp) 1.52 + { 1.53 + JS_ASSERT(isMemoryOrEffectiveAddress()); 1.54 + 1.55 + // With a zero offset, this is a plain reg-to-reg move. 1.56 + if (disp == 0 && kind_ == EFFECTIVE_ADDRESS) 1.57 + kind_ = REG; 1.58 + } 1.59 + MoveOperand(const MoveOperand &other) 1.60 + : kind_(other.kind_), 1.61 + code_(other.code_), 1.62 + disp_(other.disp_) 1.63 + { } 1.64 + bool isFloatReg() const { 1.65 + return kind_ == FLOAT_REG; 1.66 + } 1.67 + bool isGeneralReg() const { 1.68 + return kind_ == REG; 1.69 + } 1.70 + bool isMemory() const { 1.71 + return kind_ == MEMORY; 1.72 + } 1.73 + bool isEffectiveAddress() const { 1.74 + return kind_ == EFFECTIVE_ADDRESS; 1.75 + } 1.76 + bool isMemoryOrEffectiveAddress() const { 1.77 + return isMemory() || isEffectiveAddress(); 1.78 + } 1.79 + Register reg() const { 1.80 + JS_ASSERT(isGeneralReg()); 1.81 + return Register::FromCode(code_); 1.82 + } 1.83 + FloatRegister floatReg() const { 1.84 + JS_ASSERT(isFloatReg()); 1.85 + return FloatRegister::FromCode(code_); 1.86 + } 1.87 + Register base() const { 1.88 + JS_ASSERT(isMemoryOrEffectiveAddress()); 1.89 + return Register::FromCode(code_); 1.90 + } 1.91 + int32_t disp() const { 1.92 + JS_ASSERT(isMemoryOrEffectiveAddress()); 1.93 + return disp_; 1.94 + } 1.95 + 1.96 + bool operator ==(const MoveOperand &other) const { 1.97 + if (kind_ != other.kind_) 1.98 + return false; 1.99 + if (code_ != other.code_) 1.100 + return false; 1.101 + if (isMemoryOrEffectiveAddress()) 1.102 + return disp_ == other.disp_; 1.103 + return true; 1.104 + } 1.105 + bool operator !=(const MoveOperand &other) const { 1.106 + return !operator==(other); 1.107 + } 1.108 +}; 1.109 + 1.110 +// This represents a move operation. 1.111 +class MoveOp 1.112 +{ 1.113 + protected: 1.114 + MoveOperand from_; 1.115 + MoveOperand to_; 1.116 + bool cycleBegin_; 1.117 + bool cycleEnd_; 1.118 + 1.119 + public: 1.120 + enum Type { 1.121 + GENERAL, 1.122 + INT32, 1.123 + FLOAT32, 1.124 + DOUBLE 1.125 + }; 1.126 + 1.127 + protected: 1.128 + Type type_; 1.129 + 1.130 + // If cycleBegin_ is true, endCycleType_ is the type of the move at the end 1.131 + // of the cycle. For example, given these moves: 1.132 + // INT32 move a -> b 1.133 + // GENERAL move b -> a 1.134 + // the move resolver starts by copying b into a temporary location, so that 1.135 + // the last move can read it. This copy needs to use use type GENERAL. 1.136 + Type endCycleType_; 1.137 + 1.138 + public: 1.139 + MoveOp() 1.140 + { } 1.141 + MoveOp(const MoveOperand &from, const MoveOperand &to, Type type) 1.142 + : from_(from), 1.143 + to_(to), 1.144 + cycleBegin_(false), 1.145 + cycleEnd_(false), 1.146 + type_(type) 1.147 + { } 1.148 + 1.149 + bool isCycleBegin() const { 1.150 + return cycleBegin_; 1.151 + } 1.152 + bool isCycleEnd() const { 1.153 + return cycleEnd_; 1.154 + } 1.155 + const MoveOperand &from() const { 1.156 + return from_; 1.157 + } 1.158 + const MoveOperand &to() const { 1.159 + return to_; 1.160 + } 1.161 + Type type() const { 1.162 + return type_; 1.163 + } 1.164 + Type endCycleType() const { 1.165 + JS_ASSERT(isCycleBegin()); 1.166 + return endCycleType_; 1.167 + } 1.168 +}; 1.169 + 1.170 +class MoveResolver 1.171 +{ 1.172 + private: 1.173 + struct PendingMove 1.174 + : public MoveOp, 1.175 + public TempObject, 1.176 + public InlineListNode<PendingMove> 1.177 + { 1.178 + PendingMove() 1.179 + { } 1.180 + PendingMove(const MoveOperand &from, const MoveOperand &to, Type type) 1.181 + : MoveOp(from, to, type) 1.182 + { } 1.183 + 1.184 + void setCycleBegin(Type endCycleType) { 1.185 + JS_ASSERT(!isCycleBegin() && !isCycleEnd()); 1.186 + cycleBegin_ = true; 1.187 + endCycleType_ = endCycleType; 1.188 + } 1.189 + void setCycleEnd() { 1.190 + JS_ASSERT(!isCycleBegin() && !isCycleEnd()); 1.191 + cycleEnd_ = true; 1.192 + } 1.193 + }; 1.194 + 1.195 + typedef InlineList<MoveResolver::PendingMove>::iterator PendingMoveIterator; 1.196 + 1.197 + private: 1.198 + // Moves that are definitely unblocked (constants to registers). These are 1.199 + // emitted last. 1.200 + js::Vector<MoveOp, 16, SystemAllocPolicy> orderedMoves_; 1.201 + bool hasCycles_; 1.202 + 1.203 + TempObjectPool<PendingMove> movePool_; 1.204 + 1.205 + InlineList<PendingMove> pending_; 1.206 + 1.207 + PendingMove *findBlockingMove(const PendingMove *last); 1.208 + 1.209 + // Internal reset function. Does not clear lists. 1.210 + void resetState(); 1.211 + 1.212 + public: 1.213 + MoveResolver(); 1.214 + 1.215 + // Resolves a move group into two lists of ordered moves. These moves must 1.216 + // be executed in the order provided. Some moves may indicate that they 1.217 + // participate in a cycle. For every cycle there are two such moves, and it 1.218 + // is guaranteed that cycles do not nest inside each other in the list. 1.219 + // 1.220 + // After calling addMove() for each parallel move, resolve() performs the 1.221 + // cycle resolution algorithm. Calling addMove() again resets the resolver. 1.222 + bool addMove(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type); 1.223 + bool resolve(); 1.224 + 1.225 + size_t numMoves() const { 1.226 + return orderedMoves_.length(); 1.227 + } 1.228 + const MoveOp &getMove(size_t i) const { 1.229 + return orderedMoves_[i]; 1.230 + } 1.231 + bool hasCycles() const { 1.232 + return hasCycles_; 1.233 + } 1.234 + void clearTempObjectPool() { 1.235 + movePool_.clear(); 1.236 + } 1.237 + void setAllocator(TempAllocator &alloc) { 1.238 + movePool_.setAllocator(alloc); 1.239 + } 1.240 +}; 1.241 + 1.242 +} // namespace jit 1.243 +} // namespace js 1.244 + 1.245 +#endif /* jit_MoveResolver_h */