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