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 #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 ? -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 static void initLITables() __attribute__ ((constructor)); 248 static void initLITables() 249 { 250 li_table_entry_count = 0; 251 for (unsigned index = 0; index < LI_TABLE_SIZE; index++) { 252 uint32_t N = uimm(index, 12, 12); 253 uint32_t immr = uimm(index, 11, 6); 254 uint32_t imms = uimm(index, 5, 0); 255 if (expandLogicalImmediate(N, immr, imms, LITable[index])) { 256 InverseLITable[li_table_entry_count].immediate = LITable[index]; 257 InverseLITable[li_table_entry_count].encoding = index; 258 li_table_entry_count++; 259 } 260 } 261 // now sort the inverse table 262 qsort(InverseLITable, li_table_entry_count, 263 sizeof(InverseLITable[0]), compare_immediate_pair); 264 } 265 266 // public APIs provided for logical immediate lookup and reverse lookup 267 268 uint64_t logical_immediate_for_encoding(uint32_t encoding) 269 { 270 return LITable[encoding]; 271 } 272 273 uint32_t encoding_for_logical_immediate(uint64_t immediate) 274 { 275 struct li_pair pair; 276 struct li_pair *result; 277 278 pair.immediate = immediate; 279 280 result = (struct li_pair *) 281 bsearch(&pair, InverseLITable, li_table_entry_count, 282 sizeof(InverseLITable[0]), compare_immediate_pair); 283 284 if (result) { 285 return result->encoding; 286 } 287 288 return 0xffffffff; 289 } 290 291 // floating point immediates are encoded in 8 bits 292 // fpimm[7] = sign bit 293 // fpimm[6:4] = signed exponent 294 // fpimm[3:0] = fraction (assuming leading 1) 295 // i.e. F = s * 1.f * 2^(e - b) 296 297 uint64_t fp_immediate_for_encoding(uint32_t imm8, int is_dp) 298 { 299 union { 300 float fpval; 301 double dpval; 302 uint64_t val; 303 }; 304 305 uint32_t s, e, f; 306 s = (imm8 >> 7 ) & 0x1; 307 e = (imm8 >> 4) & 0x7; 308 f = imm8 & 0xf; 309 // the fp value is s * n/16 * 2r where n is 16+e 310 fpval = (16.0 + f) / 16.0; 311 // n.b. exponent is signed 312 if (e < 4) { 313 int epos = e; 314 for (int i = 0; i <= epos; i++) { 315 fpval *= 2.0; 316 } 317 } else { 318 int eneg = 7 - e; 319 for (int i = 0; i < eneg; i++) { 320 fpval /= 2.0; 321 } 322 } 323 324 if (s) { 325 fpval = -fpval; 326 } 327 if (is_dp) { 328 dpval = (double)fpval; 329 } 330 return val; 331 } 332 333 uint32_t encoding_for_fp_immediate(float immediate) 334 { 335 // given a float which is of the form 336 // 337 // s * n/16 * 2r 338 // 339 // where n is 16+f and imm1:s, imm4:f, simm3:r 340 // return the imm8 result [s:r:f] 341 // 342 343 union { 344 float fpval; 345 uint32_t val; 346 }; 347 fpval = immediate; 348 uint32_t s, r, f, res; 349 // sign bit is 31 350 s = (val >> 31) & 0x1; 351 // exponent is bits 30-23 but we only want the bottom 3 bits 352 // strictly we ought to check that the bits bits 30-25 are 353 // either all 1s or all 0s 354 r = (val >> 23) & 0x7; 355 // fraction is bits 22-0 356 f = (val >> 19) & 0xf; 357 res = (s << 7) | (r << 4) | f; 358 return res; 359 } 360