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