mirror of
https://github.com/darlinghq/darling-JavaScriptCore.git
synced 2025-04-08 18:01:37 +00:00
300 lines
9.7 KiB
C++
300 lines
9.7 KiB
C++
/*
|
|
* Copyright (C) 2012-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
|
|
|
|
namespace JSC {
|
|
|
|
ALWAYS_INLINE constexpr bool isDarwin()
|
|
{
|
|
#if OS(DARWIN)
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
ALWAYS_INLINE constexpr bool isIOS()
|
|
{
|
|
#if PLATFORM(IOS_FAMILY)
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
ALWAYS_INLINE bool isInt9(int32_t value)
|
|
{
|
|
return value == ((value << 23) >> 23);
|
|
}
|
|
|
|
template<typename Type>
|
|
ALWAYS_INLINE bool isUInt12(Type value)
|
|
{
|
|
return !(value & ~static_cast<Type>(0xfff));
|
|
}
|
|
|
|
template<int datasize>
|
|
ALWAYS_INLINE bool isValidScaledUImm12(int32_t offset)
|
|
{
|
|
int32_t maxPImm = 4095 * (datasize / 8);
|
|
if (offset < 0)
|
|
return false;
|
|
if (offset > maxPImm)
|
|
return false;
|
|
if (offset & ((datasize / 8) - 1))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
ALWAYS_INLINE bool isValidSignedImm9(int32_t value)
|
|
{
|
|
return isInt9(value);
|
|
}
|
|
|
|
class ARM64LogicalImmediate {
|
|
public:
|
|
static ARM64LogicalImmediate create32(uint32_t value)
|
|
{
|
|
// Check for 0, -1 - these cannot be encoded.
|
|
if (!value || !~value)
|
|
return InvalidLogicalImmediate;
|
|
|
|
// First look for a 32-bit pattern, then for repeating 16-bit
|
|
// patterns, 8-bit, 4-bit, and finally 2-bit.
|
|
|
|
unsigned hsb, lsb;
|
|
bool inverted;
|
|
if (findBitRange<32>(value, hsb, lsb, inverted))
|
|
return encodeLogicalImmediate<32>(hsb, lsb, inverted);
|
|
|
|
if ((value & 0xffff) != (value >> 16))
|
|
return InvalidLogicalImmediate;
|
|
value &= 0xffff;
|
|
|
|
if (findBitRange<16>(value, hsb, lsb, inverted))
|
|
return encodeLogicalImmediate<16>(hsb, lsb, inverted);
|
|
|
|
if ((value & 0xff) != (value >> 8))
|
|
return InvalidLogicalImmediate;
|
|
value &= 0xff;
|
|
|
|
if (findBitRange<8>(value, hsb, lsb, inverted))
|
|
return encodeLogicalImmediate<8>(hsb, lsb, inverted);
|
|
|
|
if ((value & 0xf) != (value >> 4))
|
|
return InvalidLogicalImmediate;
|
|
value &= 0xf;
|
|
|
|
if (findBitRange<4>(value, hsb, lsb, inverted))
|
|
return encodeLogicalImmediate<4>(hsb, lsb, inverted);
|
|
|
|
if ((value & 0x3) != (value >> 2))
|
|
return InvalidLogicalImmediate;
|
|
value &= 0x3;
|
|
|
|
if (findBitRange<2>(value, hsb, lsb, inverted))
|
|
return encodeLogicalImmediate<2>(hsb, lsb, inverted);
|
|
|
|
return InvalidLogicalImmediate;
|
|
}
|
|
|
|
static ARM64LogicalImmediate create64(uint64_t value)
|
|
{
|
|
// Check for 0, -1 - these cannot be encoded.
|
|
if (!value || !~value)
|
|
return InvalidLogicalImmediate;
|
|
|
|
// Look for a contiguous bit range.
|
|
unsigned hsb, lsb;
|
|
bool inverted;
|
|
if (findBitRange<64>(value, hsb, lsb, inverted))
|
|
return encodeLogicalImmediate<64>(hsb, lsb, inverted);
|
|
|
|
// If the high & low 32 bits are equal, we can try for a 32-bit (or narrower) pattern.
|
|
if (static_cast<uint32_t>(value) == static_cast<uint32_t>(value >> 32))
|
|
return create32(static_cast<uint32_t>(value));
|
|
return InvalidLogicalImmediate;
|
|
}
|
|
|
|
int value() const
|
|
{
|
|
ASSERT(isValid());
|
|
return m_value;
|
|
}
|
|
|
|
bool isValid() const
|
|
{
|
|
return m_value != InvalidLogicalImmediate;
|
|
}
|
|
|
|
bool is64bit() const
|
|
{
|
|
return m_value & (1 << 12);
|
|
}
|
|
|
|
private:
|
|
ARM64LogicalImmediate(int value)
|
|
: m_value(value)
|
|
{
|
|
}
|
|
|
|
// Generate a mask with bits in the range hsb..0 set, for example:
|
|
// hsb:63 = 0xffffffffffffffff
|
|
// hsb:42 = 0x000007ffffffffff
|
|
// hsb: 0 = 0x0000000000000001
|
|
static uint64_t mask(unsigned hsb)
|
|
{
|
|
ASSERT(hsb < 64);
|
|
return 0xffffffffffffffffull >> (63 - hsb);
|
|
}
|
|
|
|
template<unsigned N>
|
|
static void partialHSB(uint64_t& value, unsigned&result)
|
|
{
|
|
if (value & (0xffffffffffffffffull << N)) {
|
|
result += N;
|
|
value >>= N;
|
|
}
|
|
}
|
|
|
|
// Find the bit number of the highest bit set in a non-zero value, for example:
|
|
// 0x8080808080808080 = hsb:63
|
|
// 0x0000000000000001 = hsb: 0
|
|
// 0x000007ffffe00000 = hsb:42
|
|
static unsigned highestSetBit(uint64_t value)
|
|
{
|
|
ASSERT(value);
|
|
unsigned hsb = 0;
|
|
partialHSB<32>(value, hsb);
|
|
partialHSB<16>(value, hsb);
|
|
partialHSB<8>(value, hsb);
|
|
partialHSB<4>(value, hsb);
|
|
partialHSB<2>(value, hsb);
|
|
partialHSB<1>(value, hsb);
|
|
return hsb;
|
|
}
|
|
|
|
// This function takes a value and a bit width, where value obeys the following constraints:
|
|
// * bits outside of the width of the value must be zero.
|
|
// * bits within the width of value must neither be all clear or all set.
|
|
// The input is inspected to detect values that consist of either two or three contiguous
|
|
// ranges of bits. The output range hsb..lsb will describe the second range of the value.
|
|
// if the range is set, inverted will be false, and if the range is clear, inverted will
|
|
// be true. For example (with width 8):
|
|
// 00001111 = hsb:3, lsb:0, inverted:false
|
|
// 11110000 = hsb:3, lsb:0, inverted:true
|
|
// 00111100 = hsb:5, lsb:2, inverted:false
|
|
// 11000011 = hsb:5, lsb:2, inverted:true
|
|
template<unsigned width>
|
|
static bool findBitRange(uint64_t value, unsigned& hsb, unsigned& lsb, bool& inverted)
|
|
{
|
|
ASSERT(value & mask(width - 1));
|
|
ASSERT(value != mask(width - 1));
|
|
ASSERT(!(value & ~mask(width - 1)));
|
|
|
|
// Detect cases where the top bit is set; if so, flip all the bits & set invert.
|
|
// This halves the number of patterns we need to look for.
|
|
const uint64_t msb = 1ull << (width - 1);
|
|
if ((inverted = (value & msb)))
|
|
value ^= mask(width - 1);
|
|
|
|
// Find the highest set bit in value, generate a corresponding mask & flip all
|
|
// bits under it.
|
|
hsb = highestSetBit(value);
|
|
value ^= mask(hsb);
|
|
if (!value) {
|
|
// If this cleared the value, then the range hsb..0 was all set.
|
|
lsb = 0;
|
|
return true;
|
|
}
|
|
|
|
// Try making one more mask, and flipping the bits!
|
|
lsb = highestSetBit(value);
|
|
value ^= mask(lsb);
|
|
if (!value) {
|
|
// Success - but lsb actually points to the hsb of a third range - add one
|
|
// to get to the lsb of the mid range.
|
|
++lsb;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Encodes the set of immN:immr:imms fields found in a logical immediate.
|
|
template<unsigned width>
|
|
static int encodeLogicalImmediate(unsigned hsb, unsigned lsb, bool inverted)
|
|
{
|
|
// Check width is a power of 2!
|
|
ASSERT(!(width & (width -1)));
|
|
ASSERT(width <= 64 && width >= 2);
|
|
ASSERT(hsb >= lsb);
|
|
ASSERT(hsb < width);
|
|
|
|
int immN = 0;
|
|
int imms = 0;
|
|
int immr = 0;
|
|
|
|
// For 64-bit values this is easy - just set immN to true, and imms just
|
|
// contains the bit number of the highest set bit of the set range. For
|
|
// values with narrower widths, these are encoded by a leading set of
|
|
// one bits, followed by a zero bit, followed by the remaining set of bits
|
|
// being the high bit of the range. For a 32-bit immediate there are no
|
|
// leading one bits, just a zero followed by a five bit number. For a
|
|
// 16-bit immediate there is one one bit, a zero bit, and then a four bit
|
|
// bit-position, etc.
|
|
if (width == 64)
|
|
immN = 1;
|
|
else
|
|
imms = 63 & ~(width + width - 1);
|
|
|
|
if (inverted) {
|
|
// if width is 64 & hsb is 62, then we have a value something like:
|
|
// 0x80000000ffffffff (in this case with lsb 32).
|
|
// The ror should be by 1, imms (effectively set width minus 1) is
|
|
// 32. Set width is full width minus cleared width.
|
|
immr = (width - 1) - hsb;
|
|
imms |= (width - ((hsb - lsb) + 1)) - 1;
|
|
} else {
|
|
// if width is 64 & hsb is 62, then we have a value something like:
|
|
// 0x7fffffff00000000 (in this case with lsb 32).
|
|
// The value is effectively rol'ed by lsb, which is equivalent to
|
|
// a ror by width - lsb (or 0, in the case where lsb is 0). imms
|
|
// is hsb - lsb.
|
|
immr = (width - lsb) & (width - 1);
|
|
imms |= hsb - lsb;
|
|
}
|
|
|
|
return immN << 12 | immr << 6 | imms;
|
|
}
|
|
|
|
static constexpr int InvalidLogicalImmediate = -1;
|
|
|
|
int m_value;
|
|
};
|
|
|
|
} // namespace JSC.
|