1 /* 2 * Copyright (c) 2014, Red Hat Inc. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "utilities/globalDefinitions.hpp" 27 #include "immediate_aarch64.hpp" 28 29 // there are at most 2^13 possible logical immediate encodings 30 // however, some combinations of immr and imms are invalid 31 static const unsigned LI_TABLE_SIZE = (1 << 13); 32 33 static int li_table_entry_count; 34 35 // for forward lookup we just use a direct array lookup 36 // and assume that the cient has supplied a valid encoding 37 // table[encoding] = immediate 38 static uint64_t LITable[LI_TABLE_SIZE]; 39 40 // for reverse lookup we need a sparse map so we store a table of 41 // immediate and encoding pairs sorted by immediate value 42 43 struct li_pair { 44 uint64_t immediate; 45 uint32_t encoding; 46 }; 47 48 static struct li_pair InverseLITable[LI_TABLE_SIZE]; 49 50 // comparator to sort entries in the inverse table 51 int compare_immediate_pair(const void *i1, const void *i2) 52 { 53 struct li_pair *li1 = (struct li_pair *)i1; 54 struct li_pair *li2 = (struct li_pair *)i2; 55 if (li1->immediate < li2->immediate) { 56 return -1; 57 } 58 if (li1->immediate > li2->immediate) { 59 return 1; 60 } 61 return 0; 62 } 63 64 // helper functions used by expandLogicalImmediate 65 66 // for i = 1, ... N result<i-1> = 1 other bits are zero 67 static inline uint64_t ones(int N) 68 { 69 return (N == 64 ? (uint64_t)-1ULL : ((1ULL << N) - 1)); 70 } 71 72 /* 73 * bit twiddling helpers for instruction decode 74 */ 75 76 // 32 bit mask with bits [hi,...,lo] set 77 static inline uint32_t mask32(int hi = 31, int lo = 0) 78 { 79 int nbits = (hi + 1) - lo; 80 return ((1 << nbits) - 1) << lo; 81 } 82 83 static inline uint64_t mask64(int hi = 63, int lo = 0) 84 { 85 int nbits = (hi + 1) - lo; 86 return ((1L << nbits) - 1) << lo; 87 } 88 89 // pick bits [hi,...,lo] from val 90 static inline uint32_t pick32(uint32_t val, int hi = 31, int lo = 0) 91 { 92 return (val & mask32(hi, lo)); 93 } 94 95 // pick bits [hi,...,lo] from val 96 static inline uint64_t pick64(uint64_t val, int hi = 31, int lo = 0) 97 { 98 return (val & mask64(hi, lo)); 99 } 100 101 // mask [hi,lo] and shift down to start at bit 0 102 static inline uint32_t pickbits32(uint32_t val, int hi = 31, int lo = 0) 103 { 104 return (pick32(val, hi, lo) >> lo); 105 } 106 107 // mask [hi,lo] and shift down to start at bit 0 108 static inline uint64_t pickbits64(uint64_t val, int hi = 63, int lo = 0) 109 { 110 return (pick64(val, hi, lo) >> lo); 111 } 112 113 // result<0> to val<N> 114 static inline uint64_t pickbit(uint64_t val, int N) 115 { 116 return pickbits64(val, N, N); 117 } 118 119 static inline uint32_t uimm(uint32_t val, int hi, int lo) 120 { 121 return pickbits32(val, hi, lo); 122 } 123 124 // SPEC bits(M*N) Replicate(bits(M) x, integer N); 125 // this is just an educated guess 126 127 uint64_t replicate(uint64_t bits, int nbits, int count) 128 { 129 uint64_t result = 0; 130 // nbits may be 64 in which case we want mask to be -1 131 uint64_t mask = ones(nbits); 132 for (int i = 0; i < count ; i++) { 133 result <<= nbits; 134 result |= (bits & mask); 135 } 136 return result; 137 } 138 139 // this function writes the supplied bimm reference and returns a 140 // boolean to indicate success (1) or fail (0) because an illegal 141 // encoding must be treated as an UNALLOC instruction 142 143 // construct a 32 bit immediate value for a logical immediate operation 144 int expandLogicalImmediate(uint32_t immN, uint32_t immr, 145 uint32_t imms, uint64_t &bimm) 146 { 147 int len; // ought to be <= 6 148 uint32_t levels; // 6 bits 149 uint32_t tmask_and; // 6 bits 150 uint32_t wmask_and; // 6 bits 151 uint32_t tmask_or; // 6 bits 152 uint32_t wmask_or; // 6 bits 153 uint64_t imm64; // 64 bits 154 uint64_t tmask, wmask; // 64 bits 155 uint32_t S, R, diff; // 6 bits? 156 157 if (immN == 1) { 158 len = 6; // looks like 7 given the spec above but this cannot be! 159 } else { 160 len = 0; 161 uint32_t val = (~imms & 0x3f); 162 for (int i = 5; i > 0; i--) { 163 if (val & (1 << i)) { 164 len = i; 165 break; 166 } 167 } 168 if (len < 1) { 169 return 0; 170 } 171 // for valid inputs leading 1s in immr must be less than leading 172 // zeros in imms 173 int len2 = 0; // ought to be < len 174 uint32_t val2 = (~immr & 0x3f); 175 for (int i = 5; i > 0; i--) { 176 if (!(val2 & (1 << i))) { 177 len2 = i; 178 break; 179 } 180 } 181 if (len2 >= len) { 182 return 0; 183 } 184 } 185 186 levels = (1 << len) - 1; 187 188 if ((imms & levels) == levels) { 189 return 0; 190 } 191 192 S = imms & levels; 193 R = immr & levels; 194 195 // 6 bit arithmetic! 196 diff = S - R; 197 tmask_and = (diff | ~levels) & 0x3f; 198 tmask_or = (diff & levels) & 0x3f; 199 tmask = 0xffffffffffffffffULL; 200 201 for (int i = 0; i < 6; i++) { 202 int nbits = 1 << i; 203 uint64_t and_bit = pickbit(tmask_and, i); 204 uint64_t or_bit = pickbit(tmask_or, i); 205 uint64_t and_bits_sub = replicate(and_bit, 1, nbits); 206 uint64_t or_bits_sub = replicate(or_bit, 1, nbits); 207 uint64_t and_bits_top = (and_bits_sub << nbits) | ones(nbits); 208 uint64_t or_bits_top = (0 << nbits) | or_bits_sub; 209 210 tmask = ((tmask 211 & (replicate(and_bits_top, 2 * nbits, 32 / nbits))) 212 | replicate(or_bits_top, 2 * nbits, 32 / nbits)); 213 } 214 215 wmask_and = (immr | ~levels) & 0x3f; 216 wmask_or = (immr & levels) & 0x3f; 217 218 wmask = 0; 219 220 for (int i = 0; i < 6; i++) { 221 int nbits = 1 << i; 222 uint64_t and_bit = pickbit(wmask_and, i); 223 uint64_t or_bit = pickbit(wmask_or, i); 224 uint64_t and_bits_sub = replicate(and_bit, 1, nbits); 225 uint64_t or_bits_sub = replicate(or_bit, 1, nbits); 226 uint64_t and_bits_top = (ones(nbits) << nbits) | and_bits_sub; 227 uint64_t or_bits_top = (or_bits_sub << nbits) | 0; 228 229 wmask = ((wmask 230 & (replicate(and_bits_top, 2 * nbits, 32 / nbits))) 231 | replicate(or_bits_top, 2 * nbits, 32 / nbits)); 232 } 233 234 if (diff & (1U << 6)) { 235 imm64 = tmask & wmask; 236 } else { 237 imm64 = tmask | wmask; 238 } 239 240 241 bimm = imm64; 242 return 1; 243 } 244 245 // constructor to initialise the lookup tables 246 247 // Use a hack with MSVC as it doesn't support `__attribute__ ((constructor))` 248 // See https://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc 249 static void initLITables() NOT_WIN64(__attribute__ ((constructor))); 250 #ifdef _WIN64 251 static struct initLITables_t { initLITables_t(void) { initLITables(); } } _initLITables; 252 #endif 253 static void initLITables() 254 { 255 li_table_entry_count = 0; 256 for (unsigned index = 0; index < LI_TABLE_SIZE; index++) { 257 uint32_t N = uimm(index, 12, 12); 258 uint32_t immr = uimm(index, 11, 6); 259 uint32_t imms = uimm(index, 5, 0); 260 if (expandLogicalImmediate(N, immr, imms, LITable[index])) { 261 InverseLITable[li_table_entry_count].immediate = LITable[index]; 262 InverseLITable[li_table_entry_count].encoding = index; 263 li_table_entry_count++; 264 } 265 } 266 // now sort the inverse table 267 qsort(InverseLITable, li_table_entry_count, 268 sizeof(InverseLITable[0]), compare_immediate_pair); 269 } 270 271 // public APIs provided for logical immediate lookup and reverse lookup 272 273 uint64_t logical_immediate_for_encoding(uint32_t encoding) 274 { 275 return LITable[encoding]; 276 } 277 278 uint32_t encoding_for_logical_immediate(uint64_t immediate) 279 { 280 struct li_pair pair; 281 struct li_pair *result; 282 283 pair.immediate = immediate; 284 285 result = (struct li_pair *) 286 bsearch(&pair, InverseLITable, li_table_entry_count, 287 sizeof(InverseLITable[0]), compare_immediate_pair); 288 289 if (result) { 290 return result->encoding; 291 } 292 293 return 0xffffffff; 294 } 295 296 // floating point immediates are encoded in 8 bits 297 // fpimm[7] = sign bit 298 // fpimm[6:4] = signed exponent 299 // fpimm[3:0] = fraction (assuming leading 1) 300 // i.e. F = s * 1.f * 2^(e - b) 301 302 uint64_t fp_immediate_for_encoding(uint32_t imm8, int is_dp) 303 { 304 union { 305 float fpval; 306 double dpval; 307 uint64_t val; 308 }; 309 310 uint32_t s, e, f; 311 s = (imm8 >> 7 ) & 0x1; 312 e = (imm8 >> 4) & 0x7; 313 f = imm8 & 0xf; 314 // the fp value is s * n/16 * 2r where n is 16+e 315 fpval = (16.0 + f) / 16.0; 316 // n.b. exponent is signed 317 if (e < 4) { 318 int epos = e; 319 for (int i = 0; i <= epos; i++) { 320 fpval *= 2.0; 321 } 322 } else { 323 int eneg = 7 - e; 324 for (int i = 0; i < eneg; i++) { 325 fpval /= 2.0; 326 } 327 } 328 329 if (s) { 330 fpval = -fpval; 331 } 332 if (is_dp) { 333 dpval = (double)fpval; 334 } 335 return val; 336 } 337 338 uint32_t encoding_for_fp_immediate(float immediate) 339 { 340 // given a float which is of the form 341 // 342 // s * n/16 * 2r 343 // 344 // where n is 16+f and imm1:s, imm4:f, simm3:r 345 // return the imm8 result [s:r:f] 346 // 347 348 union { 349 float fpval; 350 uint32_t val; 351 }; 352 fpval = immediate; 353 uint32_t s, r, f, res; 354 // sign bit is 31 355 s = (val >> 31) & 0x1; 356 // exponent is bits 30-23 but we only want the bottom 3 bits 357 // strictly we ought to check that the bits bits 30-25 are 358 // either all 1s or all 0s 359 r = (val >> 23) & 0x7; 360 // fraction is bits 22-0 361 f = (val >> 19) & 0xf; 362 res = (s << 7) | (r << 4) | f; 363 return res; 364 } 365