js/src/jit/MoveResolver.h

changeset 0
6474c204b198
     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 &reg) : kind_(REG), code_(reg.code())
    1.45 +    { }
    1.46 +    explicit MoveOperand(const FloatRegister &reg) : kind_(FLOAT_REG), code_(reg.code())
    1.47 +    { }
    1.48 +    MoveOperand(const Register &reg, 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 */

mercurial