1 /* LoongArch opcode support. 2 Copyright (C) 2021-2024 Free Software Foundation, Inc. 3 Contributed by Loongson Ltd. 4 5 This file is part of the GNU opcodes library. 6 7 This library is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3, or (at your option) 10 any later version. 11 12 It is distributed in the hope that it will be useful, but WITHOUT 13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; see the file COPYING3. If not, 19 see <http://www.gnu.org/licenses/>. */ 20 #include "sysdep.h" 21 #include <stdbool.h> 22 #include "opcode/loongarch.h" 23 24 int 25 is_unsigned (const char *c_str) 26 { 27 if (c_str[0] == '0' && (c_str[1] == 'x' || c_str[1] == 'X')) 28 { 29 c_str += 2; 30 while (('a' <= *c_str && *c_str <= 'f') 31 || ('A' <= *c_str && *c_str <= 'F') 32 || ('0' <= *c_str && *c_str <= '9')) 33 c_str++; 34 } 35 else if (*c_str == '\0') 36 return 0; 37 else 38 while ('0' <= *c_str && *c_str <= '9') 39 c_str++; 40 return *c_str == '\0'; 41 } 42 43 int 44 is_signed (const char *c_str) 45 { 46 return *c_str == '-' ? is_unsigned (c_str + 1) : is_unsigned (c_str); 47 } 48 49 int 50 loongarch_get_bit_field_width (const char *bit_field, char **end) 51 { 52 int width = 0; 53 char has_specify = 0, *bit_field_1 = (char *) bit_field; 54 if (bit_field_1 && *bit_field_1 != '\0') 55 while (1) 56 { 57 strtol (bit_field_1, &bit_field_1, 10); 58 59 if (*bit_field_1 != ':') 60 break; 61 bit_field_1++; 62 63 width += strtol (bit_field_1, &bit_field_1, 10); 64 has_specify = 1; 65 66 if (*bit_field_1 != '|') 67 break; 68 bit_field_1++; 69 } 70 if (end) 71 *end = bit_field_1; 72 return has_specify ? width : -1; 73 } 74 75 int32_t 76 loongarch_decode_imm (const char *bit_field, insn_t insn, int si) 77 { 78 int32_t ret = 0; 79 uint32_t t; 80 int len = 0, width, b_start; 81 char *bit_field_1 = (char *) bit_field; 82 while (1) 83 { 84 b_start = strtol (bit_field_1, &bit_field_1, 10); 85 if (*bit_field_1 != ':') 86 break; 87 width = strtol (bit_field_1 + 1, &bit_field_1, 10); 88 len += width; 89 90 t = insn; 91 t <<= sizeof (t) * 8 - width - b_start; 92 t >>= sizeof (t) * 8 - width; 93 ret <<= width; 94 ret |= t; 95 96 if (*bit_field_1 != '|') 97 break; 98 bit_field_1++; 99 } 100 101 if (*bit_field_1 == '<' && *(++bit_field_1) == '<') 102 { 103 width = atoi (bit_field_1 + 1); 104 ret <<= width; 105 len += width; 106 } 107 else if (*bit_field_1 == '+') 108 ret += atoi (bit_field_1 + 1); 109 110 /* Extend signed bit. */ 111 if (si) 112 { 113 uint32_t sign = 1u << (len - 1); 114 ret = (ret ^ sign) - sign; 115 } 116 117 return ret; 118 } 119 120 static insn_t 121 loongarch_encode_imm (const char *bit_field, int32_t imm) 122 { 123 char *bit_field_1 = (char *) bit_field; 124 char *t = bit_field_1; 125 int width, b_start; 126 insn_t ret = 0; 127 uint32_t i; 128 uint32_t uimm = (uint32_t)imm; 129 130 width = loongarch_get_bit_field_width (t, &t); 131 if (width == -1) 132 return ret; 133 134 if (*t == '<' && *(++t) == '<') 135 width += atoi (t + 1); 136 else if (*t == '+') 137 uimm -= atoi (t + 1); 138 139 uimm = width ? (uimm << (sizeof (uimm) * 8 - width)) : 0; 140 141 while (1) 142 { 143 b_start = strtol (bit_field_1, &bit_field_1, 10); 144 if (*bit_field_1 != ':') 145 break; 146 width = strtol (bit_field_1 + 1, &bit_field_1, 10); 147 i = uimm; 148 i = width ? (i >> (sizeof (i) * 8 - width)) : 0; 149 i = (b_start == 32) ? 0 : (i << b_start); 150 ret |= i; 151 uimm = (width == 32) ? 0 : (uimm << width); 152 153 if (*bit_field_1 != '|') 154 break; 155 bit_field_1++; 156 } 157 return ret; 158 } 159 160 /* Parse such FORMAT 161 "" 162 "u" 163 "v0:5,r5:5,s10:10<<2" 164 "r0:5,r5:5,r10:5,u15:2+1" 165 "r,r,u0:5+32,u0:5+1" 166 */ 167 static int 168 loongarch_parse_format (const char *format, char *esc1s, char *esc2s, 169 const char **bit_fields) 170 { 171 size_t arg_num = 0; 172 173 if (*format == '\0') 174 goto end; 175 176 while (1) 177 { 178 /* esc1 esc2 179 for "[a-zA-Z][a-zA-Z]?" */ 180 if (('a' <= *format && *format <= 'z') 181 || ('A' <= *format && *format <= 'Z')) 182 { 183 *esc1s++ = *format++; 184 if (('a' <= *format && *format <= 'z') 185 || ('A' <= *format && *format <= 'Z')) 186 *esc2s++ = *format++; 187 else 188 *esc2s++ = '\0'; 189 } 190 else 191 return -1; 192 193 arg_num++; 194 if (MAX_ARG_NUM_PLUS_2 - 2 < arg_num) 195 /* Need larger MAX_ARG_NUM_PLUS_2. */ 196 return -1; 197 198 *bit_fields++ = format; 199 200 if ('0' <= *format && *format <= '9') 201 { 202 /* For "[0-9]+:[0-9]+(\|[0-9]+:[0-9]+)*". */ 203 while (1) 204 { 205 while ('0' <= *format && *format <= '9') 206 format++; 207 208 if (*format != ':') 209 return -1; 210 format++; 211 212 if (!('0' <= *format && *format <= '9')) 213 return -1; 214 while ('0' <= *format && *format <= '9') 215 format++; 216 217 if (*format != '|') 218 break; 219 format++; 220 } 221 222 /* For "((\+|<<)[1-9][0-9]*)?". */ 223 do 224 { 225 if (*format == '+') 226 format++; 227 else if (format[0] == '<' && format[1] == '<') 228 format += 2; 229 else 230 break; 231 232 if (!('1' <= *format && *format <= '9')) 233 return -1; 234 while ('0' <= *format && *format <= '9') 235 format++; 236 } 237 while (0); 238 } 239 240 if (*format == ',') 241 format++; 242 else if (*format == '\0') 243 break; 244 else 245 return -1; 246 } 247 248 end: 249 *esc1s = '\0'; 250 return 0; 251 } 252 253 size_t 254 loongarch_split_args_by_comma (char *args, const char *arg_strs[]) 255 { 256 size_t num = 0; 257 258 if (*args) 259 { 260 bool inquote = false; 261 arg_strs[num++] = args; 262 for (; *args; args++) 263 if (*args == '"') 264 inquote = !inquote; 265 else if (*args == ',' && !inquote) 266 { 267 if (MAX_ARG_NUM_PLUS_2 - 1 == num) 268 goto out; 269 *args = '\0'; 270 arg_strs[num++] = args + 1; 271 } 272 273 if (*(args - 1) == '"' && *arg_strs[num - 1] == '"') 274 { 275 *(args - 1) = '\0'; 276 arg_strs[num - 1] += 1; 277 } 278 } 279 out: 280 arg_strs[num] = NULL; 281 return num; 282 } 283 284 char * 285 loongarch_cat_splited_strs (const char *arg_strs[]) 286 { 287 char *ret; 288 size_t n, l; 289 290 for (l = 0, n = 0; arg_strs[n]; n++) 291 l += strlen (arg_strs[n]); 292 ret = malloc (l + n + 1); 293 if (!ret) 294 return ret; 295 296 ret[0] = '\0'; 297 if (0 < n) 298 strcat (ret, arg_strs[0]); 299 for (l = 1; l < n; l++) 300 strcat (ret, ","), strcat (ret, arg_strs[l]); 301 return ret; 302 } 303 304 insn_t 305 loongarch_foreach_args (const char *format, const char *arg_strs[], 306 int32_t (*helper) (char esc1, char esc2, 307 const char *bit_field, 308 const char *arg, void *context), 309 void *context) 310 { 311 char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1]; 312 const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1]; 313 size_t i; 314 insn_t ret = 0; 315 int ok; 316 317 ok = loongarch_parse_format (format, esc1s, esc2s, bit_fields) == 0; 318 319 /* Make sure the num of actual args is equal to the num of escape. */ 320 for (i = 0; esc1s[i] && arg_strs[i]; i++) 321 ; 322 ok = ok && !esc1s[i] && !arg_strs[i]; 323 324 if (ok && helper) 325 { 326 for (i = 0; arg_strs[i]; i++) 327 ret |= loongarch_encode_imm (bit_fields[i], 328 helper (esc1s[i], esc2s[i], 329 bit_fields[i], arg_strs[i], 330 context)); 331 ret |= helper ('\0', '\0', NULL, NULL, context); 332 } 333 334 return ret; 335 } 336 337 int 338 loongarch_check_format (const char *format) 339 { 340 char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1]; 341 const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1]; 342 343 if (!format) 344 return -1; 345 346 return loongarch_parse_format (format, esc1s, esc2s, bit_fields); 347 } 348 349 int 350 loongarch_check_macro (const char *format, const char *macro) 351 { 352 int num_of_args; 353 char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1]; 354 const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1]; 355 356 if (!format || !macro 357 || loongarch_parse_format (format, esc1s, esc2s, bit_fields) != 0) 358 return -1; 359 360 for (num_of_args = 0; esc1s[num_of_args]; num_of_args++) 361 ; 362 363 for (; macro[0]; macro++) 364 if (macro[0] == '%') 365 { 366 macro++; 367 if ('1' <= macro[0] && macro[0] <= '9') 368 { 369 if (num_of_args < macro[0] - '0') 370 /* Out of args num. */ 371 return -1; 372 } 373 else if (macro[0] == 'f') 374 ; 375 else if (macro[0] == '%') 376 ; 377 else 378 return -1; 379 } 380 return 0; 381 } 382 383 static const char * 384 I (char esc_ch1 ATTRIBUTE_UNUSED, char esc_ch2 ATTRIBUTE_UNUSED, 385 const char *c_str) 386 { 387 return c_str; 388 } 389 390 char * 391 loongarch_expand_macro_with_format_map ( 392 const char *format, const char *macro, const char *const arg_strs[], 393 const char *(*map) (char esc1, char esc2, const char *arg), 394 char *(*helper) (const char *const arg_strs[], void *context), void *context, 395 size_t len_str) 396 { 397 char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1]; 398 const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1]; 399 const char *src; 400 char *dest; 401 402 /* The expanded macro character length does not exceed 1000, and number of 403 label is 6 at most in the expanded macro. The len_str is the length of 404 str. */ 405 char *buffer =(char *) malloc(1024 + 6 * len_str); 406 407 if (format) 408 loongarch_parse_format (format, esc1s, esc2s, bit_fields); 409 410 src = macro; 411 dest = buffer; 412 413 while (*src) 414 if (*src == '%') 415 { 416 src++; 417 if ('1' <= *src && *src <= '9') 418 { 419 size_t i = *src - '1'; 420 const char *t = map (esc1s[i], esc2s[i], arg_strs[i]); 421 while (*t) 422 *dest++ = *t++; 423 } 424 else if (*src == '%') 425 *dest++ = '%'; 426 else if (*src == 'f' && helper) 427 { 428 char *b, *t; 429 t = b = (*helper) (arg_strs, context); 430 if (b) 431 { 432 while (*t) 433 *dest++ = *t++; 434 free (b); 435 } 436 } 437 src++; 438 } 439 else 440 *dest++ = *src++; 441 442 *dest = '\0'; 443 return buffer; 444 } 445 446 char * 447 loongarch_expand_macro (const char *macro, const char *const arg_strs[], 448 char *(*helper) (const char *const arg_strs[], 449 void *context), 450 void *context, size_t len_str) 451 { 452 return loongarch_expand_macro_with_format_map (NULL, macro, arg_strs, I, 453 helper, context, len_str); 454 } 455 456 size_t 457 loongarch_bits_imm_needed (int64_t imm, int si) 458 { 459 size_t ret; 460 if (si) 461 { 462 if (imm < 0) 463 { 464 uint64_t uimm = (uint64_t) imm; 465 uint64_t uimax = UINT64_C (1) << 63; 466 for (ret = 0; (uimm & uimax) != 0; uimm <<= 1, ret++) 467 ; 468 ret = 64 - ret + 1; 469 } 470 else 471 ret = loongarch_bits_imm_needed (imm, 0) + 1; 472 } 473 else 474 { 475 uint64_t t = imm; 476 for (ret = 0; t; t >>= 1, ret++) 477 ; 478 } 479 return ret; 480 } 481 482 void 483 loongarch_eliminate_adjacent_repeat_char (char *dest, char c) 484 { 485 if (c == '\0') 486 return; 487 char *src = dest; 488 while (*dest) 489 { 490 while (src[0] == c && src[0] == src[1]) 491 src++; 492 *dest++ = *src++; 493 } 494 } 495