1static std::set<uint64> ValidBitmaskImmSet = { 2#include "valid_bitmask_imm.txt" 3}; 4constexpr uint32 kMaxBitTableSize = 5; 5constexpr std::array<uint64, kMaxBitTableSize> bitmaskImmMultTable = { 6 0x0000000100000001UL, 0x0001000100010001UL, 0x0101010101010101UL, 0x1111111111111111UL, 0x5555555555555555UL, 7}; 8 9bool IsBitSizeImmediate(uint64 val, uint32 bitLen, uint32 nLowerZeroBits) { 10 /* mask1 is a 64bits number that is all 1 shifts left size bits */ 11 const uint64 mask1 = 0xffffffffffffffffUL << bitLen; 12 /* mask2 is a 64 bits number that nlowerZeroBits are all 1, higher bits aro all 0 */ 13 uint64 mask2 = (1UL << static_cast<uint64>(nLowerZeroBits)) - 1UL; 14 return (mask2 & val) == 0UL && (mask1 & ((static_cast<uint64>(val)) >> nLowerZeroBits)) == 0UL; 15}; 16 17bool IsBitmaskImmediate(uint64 val, uint32 bitLen) { 18 DEBUG_ASSERT(val != 0, "IsBitmaskImmediate() don's accept 0 or -1"); 19 DEBUG_ASSERT(static_cast<int64>(val) != -1, "IsBitmaskImmediate() don's accept 0 or -1"); 20 if ((bitLen == k32BitSize) && (static_cast<int32>(val) == -1)) { 21 return false; 22 } 23 uint64 val2 = val; 24 if (bitLen == k32BitSize) { 25 val2 = (val2 << k32BitSize) | (val2 & ((1ULL << k32BitSize) - 1)); 26 } 27 bool expectedOutcome = (ValidBitmaskImmSet.find(val2) != ValidBitmaskImmSet.end()); 28 29 if ((val & 0x1) != 0) { 30 /* 31 * we want to work with 32 * 0000000000000000000000000000000000000000000001100000000000000000 33 * instead of 34 * 1111111111111111111111111111111111111111111110011111111111111111 35 */ 36 val = ~val; 37 } 38 39 if (bitLen == k32BitSize) { 40 val = (val << k32BitSize) | (val & ((1ULL << k32BitSize) - 1)); 41 } 42 43 /* get the least significant bit set and add it to 'val' */ 44 uint64 tmpVal = val + (val & static_cast<uint64>(UINT64_MAX - val + 1)); 45 46 /* now check if tmp is a power of 2 or tmpVal==0. */ 47 tmpVal = tmpVal & (tmpVal - 1); 48 if (tmpVal == 0) { 49 if (!expectedOutcome) { 50 LogInfo::MapleLogger() << "0x" << std::hex << std::setw(static_cast<int>(k16ByteSize)) << 51 std::setfill('0') << static_cast<uint64>(val) << "\n"; 52 return false; 53 } 54 DEBUG_ASSERT(expectedOutcome, "incorrect implementation: not valid value but returning true"); 55 /* power of two or zero ; return true */ 56 return true; 57 } 58 59 int32 p0 = __builtin_ctzll(val); 60 int32 p1 = __builtin_ctzll(tmpVal); 61 int64 diff = p1 - p0; 62 63 /* check if diff is a power of two; return false if not. */ 64 if ((static_cast<uint64>(diff) & (static_cast<uint64>(diff) - 1)) != 0) { 65 DEBUG_ASSERT(!expectedOutcome, "incorrect implementation: valid value but returning false"); 66 return false; 67 } 68 69 int32 logDiff = __builtin_ctzll(static_cast<uint64>(diff)); 70 int64 pattern = static_cast<int64>(val & ((1ULL << static_cast<uint64>(diff)) - 1)); 71#if DEBUG 72 bool ret = (val == pattern * bitmaskImmMultTable[kMaxBitTableSize - logDiff]); 73 DEBUG_ASSERT(expectedOutcome == ret, "incorrect implementation: return value does not match expected outcome"); 74 return ret; 75#else 76 return val == pattern * bitmaskImmMultTable[kMaxBitTableSize - logDiff]; 77#endif 78} 79 80bool Imm12BitValid(int64 value) { 81 bool result = IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal12Bits, 0); 82 // for target linux-aarch64-gnu 83 result = result || IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal12Bits, kMaxImmVal12Bits); 84 return result; 85} 86 87bool Imm12BitMaskValid(int64 value) { 88 if (value == 0 || static_cast<int64>(value) == -1) { 89 return true; 90 } 91 return IsBitmaskImmediate(static_cast<uint64>(value), k32BitSize); 92} 93 94bool Imm13BitValid(int64 value) { 95 bool result = IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal13Bits, 0); 96 // for target linux-aarch64-gnu 97 result = result || IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal13Bits, kMaxImmVal13Bits); 98 return result; 99} 100 101bool Imm13BitMaskValid(int64 value) { 102 if (value == 0 || static_cast<int64>(value) == -1) { 103 return true; 104 } 105 return IsBitmaskImmediate(static_cast<uint64>(value), k64BitSize); 106} 107 108bool Imm16BitValid(int64 value) { 109 bool result = IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal16Bits, 0); 110 /* 111 * for target linux-aarch64-gnu 112 * aarch64 assembly takes up to 24-bits immediate, generating 113 * either cmp or cmp with shift 12 encoding 114 */ 115 result = result || IsBitSizeImmediate(static_cast<uint64>(value), kMaxImmVal12Bits, kMaxImmVal12Bits); 116 return result; 117} 118 119/* 120 * 8bit : 0 121 * halfword : 1 122 * 32bit - word : 2 123 * 64bit - word : 3 124 * 128bit- word : 4 125 */ 126bool StrLdrSignedOfstValid(int64 value, uint32 wordSize) { 127 if (value <= k256BitSize && value >= kNegative256BitSize) { 128 return true; 129 } else if ((value > k256BitSize) && (value <= kMaxPimm[wordSize])) { 130 uint64 mask = (1U << wordSize) - 1U; 131 return (static_cast<uint64>(value) & mask) ? false : true; 132 } 133 return false; 134} 135 136 137bool StrLdr8ImmValid(int64 value) { 138 return StrLdrSignedOfstValid(value, 0); 139} 140 141bool StrLdr16ImmValid(int64 value) { 142 return StrLdrSignedOfstValid(value, k1ByteSize); 143} 144 145bool StrLdr32ImmValid(int64 value) { 146 return StrLdrSignedOfstValid(value, k2ByteSize); 147} 148 149bool StrLdr32PairImmValid(int64 value) { 150 if ((value <= kMaxSimm32Pair) && (value >= kMinSimm32)) { 151 return (static_cast<uint64>(value) & 3) ? false : true; 152 } 153 return false; 154} 155 156bool StrLdr64ImmValid(int64 value) { 157 return StrLdrSignedOfstValid(value, k3ByteSize); 158} 159 160bool StrLdr64PairImmValid(int64 value) { 161 if (value <= kMaxSimm64Pair && (value >= kMinSimm64)) { 162 return (static_cast<uint64>(value) & 7) ? false : true; 163 } 164 return false; 165} 166 167bool StrLdr128ImmValid(int64 value) { 168 return StrLdrSignedOfstValid(value, k4ByteSize); 169} 170 171bool StrLdr128PairImmValid(int64 value) { 172 if (value < k1024BitSize && (value >= kNegative1024BitSize)) { 173 return (static_cast<uint64>(value) & 0xf) ? false : true; 174 } 175 return false; 176} 177