| /* |
| * Copyright (C) 2015-2019 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #pragma once |
| |
| #if ENABLE(B3_JIT) |
| |
| #include "B3Bank.h" |
| #include "FPRInfo.h" |
| #include "GPRInfo.h" |
| #include "Reg.h" |
| #include <wtf/HashMap.h> |
| |
| namespace JSC { namespace B3 { namespace Air { |
| |
| class Arg; |
| class Code; |
| |
| // A Tmp is a generalization of a register. It can be used to refer to any GPR or FPR. It can also |
| // be used to refer to an unallocated register (i.e. a temporary). Like many Air classes, we use |
| // deliberately terse naming since we will have to use this name a lot. |
| |
| class Tmp { |
| public: |
| constexpr Tmp() |
| : m_value(0) |
| { |
| } |
| |
| explicit Tmp(Reg reg) |
| { |
| if (reg) { |
| if (reg.isGPR()) |
| m_value = encodeGPR(reg.gpr()); |
| else |
| m_value = encodeFPR(reg.fpr()); |
| } else |
| m_value = 0; |
| } |
| |
| explicit Tmp(const Arg&); |
| |
| static Tmp gpTmpForIndex(unsigned index) |
| { |
| Tmp result; |
| result.m_value = encodeGPTmp(index); |
| return result; |
| } |
| |
| static Tmp fpTmpForIndex(unsigned index) |
| { |
| Tmp result; |
| result.m_value = encodeFPTmp(index); |
| return result; |
| } |
| |
| static Tmp tmpForIndex(Bank bank, unsigned index) |
| { |
| if (bank == GP) |
| return gpTmpForIndex(index); |
| ASSERT(bank == FP); |
| return fpTmpForIndex(index); |
| } |
| |
| explicit operator bool() const { return !!m_value; } |
| |
| bool isGP() const |
| { |
| return isEncodedGP(m_value); |
| } |
| |
| bool isFP() const |
| { |
| return isEncodedFP(m_value); |
| } |
| |
| // For null tmps, returns GP. |
| Bank bank() const |
| { |
| return isFP() ? FP : GP; |
| } |
| |
| bool isGPR() const |
| { |
| return isEncodedGPR(m_value); |
| } |
| |
| bool isFPR() const |
| { |
| return isEncodedFPR(m_value); |
| } |
| |
| bool isReg() const |
| { |
| return isGPR() || isFPR(); |
| } |
| |
| GPRReg gpr() const |
| { |
| return decodeGPR(m_value); |
| } |
| |
| FPRReg fpr() const |
| { |
| return decodeFPR(m_value); |
| } |
| |
| Reg reg() const |
| { |
| if (isGP()) |
| return gpr(); |
| return fpr(); |
| } |
| |
| bool hasTmpIndex() const |
| { |
| return !isReg(); |
| } |
| |
| unsigned gpTmpIndex() const |
| { |
| return decodeGPTmp(m_value); |
| } |
| |
| unsigned fpTmpIndex() const |
| { |
| return decodeFPTmp(m_value); |
| } |
| |
| unsigned tmpIndex(Bank bank) const |
| { |
| if (bank == GP) |
| return gpTmpIndex(); |
| ASSERT(bank == FP); |
| return fpTmpIndex(); |
| } |
| |
| unsigned tmpIndex() const |
| { |
| if (isGP()) |
| return gpTmpIndex(); |
| return fpTmpIndex(); |
| } |
| |
| template<Bank bank> class Indexed; |
| template<Bank bank> class AbsolutelyIndexed; |
| class LinearlyIndexed; |
| |
| template<Bank bank> |
| Indexed<bank> indexed() const; |
| |
| template<Bank bank> |
| AbsolutelyIndexed<bank> absolutelyIndexed() const; |
| |
| LinearlyIndexed linearlyIndexed(Code&) const; |
| |
| static unsigned indexEnd(Code&, Bank); |
| static unsigned absoluteIndexEnd(Code&, Bank); |
| static unsigned linearIndexEnd(Code&); |
| |
| bool isAlive() const |
| { |
| return !!*this; |
| } |
| |
| bool operator==(const Tmp& other) const |
| { |
| return m_value == other.m_value; |
| } |
| |
| bool operator!=(const Tmp& other) const |
| { |
| return !(*this == other); |
| } |
| |
| void dump(PrintStream& out) const; |
| |
| Tmp(WTF::HashTableDeletedValueType) |
| : m_value(std::numeric_limits<int>::max()) |
| { |
| } |
| |
| bool isHashTableDeletedValue() const |
| { |
| return *this == Tmp(WTF::HashTableDeletedValue); |
| } |
| |
| unsigned hash() const |
| { |
| return WTF::IntHash<int>::hash(m_value); |
| } |
| |
| unsigned internalValue() const { return static_cast<unsigned>(m_value); } |
| |
| static Tmp tmpForInternalValue(unsigned index) |
| { |
| Tmp result; |
| result.m_value = static_cast<int>(index); |
| return result; |
| } |
| |
| static Tmp tmpForAbsoluteIndex(Bank, unsigned); |
| |
| static Tmp tmpForLinearIndex(Code&, unsigned); |
| |
| private: |
| static int encodeGP(unsigned index) |
| { |
| return 1 + index; |
| } |
| |
| static int encodeFP(unsigned index) |
| { |
| return -1 - index; |
| } |
| |
| static int encodeGPR(GPRReg gpr) |
| { |
| return encodeGP(gpr - MacroAssembler::firstRegister()); |
| } |
| |
| static int encodeFPR(FPRReg fpr) |
| { |
| return encodeFP(fpr - MacroAssembler::firstFPRegister()); |
| } |
| |
| static int encodeGPTmp(unsigned index) |
| { |
| return encodeGPR(MacroAssembler::lastRegister()) + 1 + index; |
| } |
| |
| static int encodeFPTmp(unsigned index) |
| { |
| return encodeFPR(MacroAssembler::lastFPRegister()) - 1 - index; |
| } |
| |
| static bool isEncodedGP(int value) |
| { |
| return value > 0; |
| } |
| |
| static bool isEncodedFP(int value) |
| { |
| return value < 0; |
| } |
| |
| static bool isEncodedGPR(int value) |
| { |
| return isEncodedGP(value) && value <= encodeGPR(MacroAssembler::lastRegister()); |
| } |
| |
| static bool isEncodedFPR(int value) |
| { |
| return isEncodedFP(value) && value >= encodeFPR(MacroAssembler::lastFPRegister()); |
| } |
| |
| static bool isEncodedGPTmp(int value) |
| { |
| return isEncodedGP(value) && !isEncodedGPR(value); |
| } |
| |
| static bool isEncodedFPTmp(int value) |
| { |
| return isEncodedFP(value) && !isEncodedFPR(value); |
| } |
| |
| static GPRReg decodeGPR(int value) |
| { |
| ASSERT(isEncodedGPR(value)); |
| return static_cast<GPRReg>( |
| (value - encodeGPR(MacroAssembler::firstRegister())) + MacroAssembler::firstRegister()); |
| } |
| |
| static FPRReg decodeFPR(int value) |
| { |
| ASSERT(isEncodedFPR(value)); |
| return static_cast<FPRReg>( |
| (encodeFPR(MacroAssembler::firstFPRegister()) - value) + |
| MacroAssembler::firstFPRegister()); |
| } |
| |
| static unsigned decodeGPTmp(int value) |
| { |
| ASSERT(isEncodedGPTmp(value)); |
| return value - (encodeGPR(MacroAssembler::lastRegister()) + 1); |
| } |
| |
| static unsigned decodeFPTmp(int value) |
| { |
| ASSERT(isEncodedFPTmp(value)); |
| return (encodeFPR(MacroAssembler::lastFPRegister()) - 1) - value; |
| } |
| |
| // 0: empty Tmp |
| // positive: GPRs and then GP temps. |
| // negative: FPRs and then FP temps. |
| int m_value; |
| }; |
| |
| struct TmpHash { |
| static unsigned hash(const Tmp& key) { return key.hash(); } |
| static bool equal(const Tmp& a, const Tmp& b) { return a == b; } |
| static constexpr bool safeToCompareToEmptyOrDeleted = true; |
| }; |
| |
| } } } // namespace JSC::B3::Air |
| |
| namespace WTF { |
| |
| template<typename T> struct DefaultHash; |
| template<> struct DefaultHash<JSC::B3::Air::Tmp> { |
| typedef JSC::B3::Air::TmpHash Hash; |
| }; |
| |
| template<typename T> struct HashTraits; |
| template<> struct HashTraits<JSC::B3::Air::Tmp> : SimpleClassHashTraits<JSC::B3::Air::Tmp> { }; |
| |
| } // namespace WTF |
| |
| #endif // ENABLE(B3_JIT) |