1 /* Common hooks for RISC-V. 2 Copyright (C) 2016-2020 Free Software Foundation, Inc. 3 4 This file is part of GCC. 5 6 GCC is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 GCC is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GCC; see the file COPYING3. If not see 18 <http://www.gnu.org/licenses/>. */ 19 20 #include <sstream> 21 22 #define INCLUDE_STRING 23 #include "config.h" 24 #include "system.h" 25 #include "coretypes.h" 26 #include "tm.h" 27 #include "common/common-target.h" 28 #include "common/common-target-def.h" 29 #include "opts.h" 30 #include "flags.h" 31 #include "diagnostic-core.h" 32 #include "config/riscv/riscv-protos.h" 33 34 #define RISCV_DONT_CARE_VERSION -1 35 36 /* Subset info. */ 37 struct riscv_subset_t 38 { 39 riscv_subset_t (); 40 41 std::string name; 42 int major_version; 43 int minor_version; 44 struct riscv_subset_t *next; 45 }; 46 47 /* Subset list. */ 48 class riscv_subset_list 49 { 50 private: 51 /* Original arch string. */ 52 const char *m_arch; 53 54 /* Location of arch string, used for report error. */ 55 location_t m_loc; 56 57 /* Head of subset info list. */ 58 riscv_subset_t *m_head; 59 60 /* Tail of subset info list. */ 61 riscv_subset_t *m_tail; 62 63 /* X-len of m_arch. */ 64 unsigned m_xlen; 65 66 riscv_subset_list (const char *, location_t); 67 68 const char *parsing_subset_version (const char *, unsigned *, unsigned *, 69 unsigned, unsigned, bool); 70 71 const char *parse_std_ext (const char *); 72 73 const char *parse_sv_or_non_std_ext (const char *, const char *, 74 const char *); 75 76 public: 77 ~riscv_subset_list (); 78 79 void add (const char *, int, int); 80 81 riscv_subset_t *lookup (const char *, 82 int major_version = RISCV_DONT_CARE_VERSION, 83 int minor_version = RISCV_DONT_CARE_VERSION) const; 84 85 std::string to_string () const; 86 87 unsigned xlen() const {return m_xlen;}; 88 89 static riscv_subset_list *parse (const char *, location_t); 90 91 }; 92 93 static const char *riscv_supported_std_ext (void); 94 95 static riscv_subset_list *current_subset_list = NULL; 96 97 riscv_subset_t::riscv_subset_t () 98 : name (), major_version (0), minor_version (0), next (NULL) 99 { 100 } 101 102 riscv_subset_list::riscv_subset_list (const char *arch, location_t loc) 103 : m_arch (arch), m_loc (loc), m_head (NULL), m_tail (NULL), m_xlen (0) 104 { 105 } 106 107 riscv_subset_list::~riscv_subset_list () 108 { 109 if (!m_head) 110 return; 111 112 riscv_subset_t *item = this->m_head; 113 while (item != NULL) 114 { 115 riscv_subset_t *next = item->next; 116 delete item; 117 item = next; 118 } 119 } 120 121 /* Add new subset to list. */ 122 123 void 124 riscv_subset_list::add (const char *subset, int major_version, 125 int minor_version) 126 { 127 riscv_subset_t *s = new riscv_subset_t (); 128 129 if (m_head == NULL) 130 m_head = s; 131 132 s->name = subset; 133 s->major_version = major_version; 134 s->minor_version = minor_version; 135 s->next = NULL; 136 137 if (m_tail != NULL) 138 m_tail->next = s; 139 140 m_tail = s; 141 } 142 143 /* Convert subset info to string with explicit version info. */ 144 145 std::string 146 riscv_subset_list::to_string () const 147 { 148 std::ostringstream oss; 149 oss << "rv" << m_xlen; 150 151 bool first = true; 152 riscv_subset_t *subset = m_head; 153 154 while (subset != NULL) 155 { 156 if (!first) 157 oss << '_'; 158 first = false; 159 160 oss << subset->name 161 << subset->major_version 162 << 'p' 163 << subset->minor_version; 164 subset = subset->next; 165 } 166 167 return oss.str (); 168 } 169 170 /* Find subset in list with version checking, return NULL if not found. 171 major/minor version checking can be ignored if major_version/minor_version 172 is RISCV_DONT_CARE_VERSION. */ 173 174 riscv_subset_t * 175 riscv_subset_list::lookup (const char *subset, int major_version, 176 int minor_version) const 177 { 178 riscv_subset_t *s; 179 180 for (s = m_head; s != NULL; s = s->next) 181 if (strcasecmp (s->name.c_str (), subset) == 0) 182 { 183 if ((major_version != RISCV_DONT_CARE_VERSION) 184 && (s->major_version != major_version)) 185 return NULL; 186 187 if ((minor_version != RISCV_DONT_CARE_VERSION) 188 && (s->minor_version != minor_version)) 189 return NULL; 190 191 return s; 192 } 193 194 return s; 195 } 196 197 /* Return string which contains all supported standard extensions in 198 canonical order. */ 199 200 static const char * 201 riscv_supported_std_ext (void) 202 { 203 return "mafdqlcbjtpvn"; 204 } 205 206 /* Parsing subset version. 207 208 Return Value: 209 Points to the end of version 210 211 Arguments: 212 `p`: Current parsing position. 213 `major_version`: Parsing result of major version, using 214 default_major_version if version is not present in arch string. 215 `minor_version`: Parsing result of minor version, set to 0 if version is 216 not present in arch string, but set to `default_minor_version` if 217 `major_version` using default_major_version. 218 `default_major_version`: Default major version. 219 `default_minor_version`: Default minor version. 220 `std_ext_p`: True if parsing std extension. */ 221 222 const char * 223 riscv_subset_list::parsing_subset_version (const char *p, 224 unsigned *major_version, 225 unsigned *minor_version, 226 unsigned default_major_version, 227 unsigned default_minor_version, 228 bool std_ext_p) 229 { 230 bool major_p = true; 231 unsigned version = 0; 232 unsigned major = 0; 233 unsigned minor = 0; 234 char np; 235 236 for (; *p; ++p) 237 { 238 if (*p == 'p') 239 { 240 np = *(p + 1); 241 242 if (!ISDIGIT (np)) 243 { 244 /* Might be beginning of `p` extension. */ 245 if (std_ext_p) 246 { 247 *major_version = version; 248 *minor_version = 0; 249 return p; 250 } 251 else 252 { 253 error_at (m_loc, "%<-march=%s%>: Expect number " 254 "after %<%dp%>.", m_arch, version); 255 return NULL; 256 } 257 } 258 259 major = version; 260 major_p = false; 261 version = 0; 262 } 263 else if (ISDIGIT (*p)) 264 version = (version * 10) + (*p - '0'); 265 else 266 break; 267 } 268 269 if (major_p) 270 major = version; 271 else 272 minor = version; 273 274 if (major == 0 && minor == 0) 275 { 276 /* We didn't find any version string, use default version. */ 277 *major_version = default_major_version; 278 *minor_version = default_minor_version; 279 } 280 else 281 { 282 *major_version = major; 283 *minor_version = minor; 284 } 285 return p; 286 } 287 288 /* Parsing function for standard extensions. 289 290 Return Value: 291 Points to the end of extensions. 292 293 Arguments: 294 `p`: Current parsing position. */ 295 296 const char * 297 riscv_subset_list::parse_std_ext (const char *p) 298 { 299 const char *all_std_exts = riscv_supported_std_ext (); 300 const char *std_exts = all_std_exts; 301 302 unsigned major_version = 0; 303 unsigned minor_version = 0; 304 char std_ext = '\0'; 305 306 /* First letter must start with i, e or g. */ 307 switch (*p) 308 { 309 case 'i': 310 p++; 311 p = parsing_subset_version (p, &major_version, &minor_version, 312 /* default_major_version= */ 2, 313 /* default_minor_version= */ 0, 314 /* std_ext_p= */ true); 315 add ("i", major_version, minor_version); 316 break; 317 318 case 'e': 319 p++; 320 p = parsing_subset_version (p, &major_version, &minor_version, 321 /* default_major_version= */ 1, 322 /* default_minor_version= */ 9, 323 /* std_ext_p= */ true); 324 325 add ("e", major_version, minor_version); 326 327 if (m_xlen > 32) 328 { 329 error_at (m_loc, "%<-march=%s%>: rv%de is not a valid base ISA", 330 m_arch, m_xlen); 331 return NULL; 332 } 333 break; 334 335 case 'g': 336 p++; 337 p = parsing_subset_version (p, &major_version, &minor_version, 338 /* default_major_version= */ 2, 339 /* default_minor_version= */ 0, 340 /* std_ext_p= */ true); 341 add ("i", major_version, minor_version); 342 343 for (; *std_exts != 'q'; std_exts++) 344 { 345 const char subset[] = {*std_exts, '\0'}; 346 add (subset, major_version, minor_version); 347 } 348 break; 349 350 default: 351 error_at (m_loc, "%<-march=%s%>: first ISA subset must be %<e%>, " 352 "%<i%> or %<g%>", m_arch); 353 return NULL; 354 } 355 356 while (*p) 357 { 358 char subset[2] = {0, 0}; 359 360 if (*p == 'x' || *p == 's') 361 break; 362 363 if (*p == '_') 364 { 365 p++; 366 continue; 367 } 368 369 std_ext = *p; 370 371 /* Checking canonical order. */ 372 while (*std_exts && std_ext != *std_exts) 373 std_exts++; 374 375 if (std_ext != *std_exts) 376 { 377 if (strchr (all_std_exts, std_ext) == NULL) 378 error_at (m_loc, "%<-march=%s%>: unsupported ISA subset %<%c%>", 379 m_arch, *p); 380 else 381 error_at (m_loc, 382 "%<-march=%s%>: ISA string is not in canonical order. " 383 "%<%c%>", m_arch, *p); 384 return NULL; 385 } 386 387 std_exts++; 388 389 p++; 390 p = parsing_subset_version (p, &major_version, &minor_version, 391 /* default_major_version= */ 2, 392 /* default_minor_version= */ 0, 393 /* std_ext_p= */ true); 394 395 subset[0] = std_ext; 396 397 add (subset, major_version, minor_version); 398 } 399 return p; 400 } 401 402 /* Parsing function for non-standard and supervisor extensions. 403 404 Return Value: 405 Points to the end of extensions. 406 407 Arguments: 408 `p`: Current parsing position. 409 `ext_type`: What kind of extensions, 'x', 's' or 'sx'. 410 `ext_type_str`: Full name for kind of extension. */ 411 412 const char * 413 riscv_subset_list::parse_sv_or_non_std_ext (const char *p, 414 const char *ext_type, 415 const char *ext_type_str) 416 { 417 unsigned major_version = 0; 418 unsigned minor_version = 0; 419 size_t ext_type_len = strlen (ext_type); 420 421 while (*p) 422 { 423 if (*p == '_') 424 { 425 p++; 426 continue; 427 } 428 429 if (strncmp (p, ext_type, ext_type_len) != 0) 430 break; 431 432 /* It's non-standard supervisor extension if it prefix with sx. */ 433 if ((ext_type[0] == 's') && (ext_type_len == 1) 434 && (*(p + 1) == 'x')) 435 break; 436 437 char *subset = xstrdup (p); 438 char *q = subset; 439 const char *end_of_version; 440 441 while (*++q != '\0' && *q != '_' && !ISDIGIT (*q)) 442 ; 443 444 end_of_version 445 = parsing_subset_version (q, &major_version, &minor_version, 446 /* default_major_version= */ 2, 447 /* default_minor_version= */ 0, 448 /* std_ext_p= */ FALSE); 449 450 *q = '\0'; 451 452 add (subset, major_version, minor_version); 453 free (subset); 454 p += end_of_version - subset; 455 456 if (*p != '\0' && *p != '_') 457 { 458 error_at (m_loc, "%<-march=%s%>: %s must separate with _", 459 m_arch, ext_type_str); 460 return NULL; 461 } 462 } 463 464 return p; 465 } 466 467 /* Parsing arch string to subset list, return NULL if parsing failed. */ 468 469 riscv_subset_list * 470 riscv_subset_list::parse (const char *arch, location_t loc) 471 { 472 riscv_subset_list *subset_list = new riscv_subset_list (arch, loc); 473 const char *p = arch; 474 if (strncmp (p, "rv32", 4) == 0) 475 { 476 subset_list->m_xlen = 32; 477 p += 4; 478 } 479 else if (strncmp (p, "rv64", 4) == 0) 480 { 481 subset_list->m_xlen = 64; 482 p += 4; 483 } 484 else 485 { 486 error_at (loc, "%<-march=%s%>: ISA string must begin with rv32 or rv64", 487 arch); 488 goto fail; 489 } 490 491 /* Parsing standard extension. */ 492 p = subset_list->parse_std_ext (p); 493 494 if (p == NULL) 495 goto fail; 496 497 /* Parsing non-standard extension. */ 498 p = subset_list->parse_sv_or_non_std_ext (p, "x", "non-standard extension"); 499 500 if (p == NULL) 501 goto fail; 502 503 /* Parsing supervisor extension. */ 504 p = subset_list->parse_sv_or_non_std_ext (p, "s", "supervisor extension"); 505 506 if (p == NULL) 507 goto fail; 508 509 /* Parsing non-standard supervisor extension. */ 510 p = subset_list->parse_sv_or_non_std_ext 511 (p, "sx", "non-standard supervisor extension"); 512 513 if (p == NULL) 514 goto fail; 515 516 if (*p != '\0') 517 { 518 error_at (loc, "%<-march=%s%>: unexpected ISA string at end: %qs", 519 arch, p); 520 goto fail; 521 } 522 523 return subset_list; 524 525 fail: 526 delete subset_list; 527 return NULL; 528 } 529 530 /* Return the current arch string. */ 531 532 std::string 533 riscv_arch_str () 534 { 535 gcc_assert (current_subset_list); 536 return current_subset_list->to_string (); 537 } 538 539 /* Parse a RISC-V ISA string into an option mask. Must clear or set all arch 540 dependent mask bits, in case more than one -march string is passed. */ 541 542 static void 543 riscv_parse_arch_string (const char *isa, int *flags, location_t loc) 544 { 545 riscv_subset_list *subset_list; 546 subset_list = riscv_subset_list::parse (isa, loc); 547 if (!subset_list) 548 return; 549 550 if (subset_list->xlen () == 32) 551 *flags &= ~MASK_64BIT; 552 else if (subset_list->xlen () == 64) 553 *flags |= MASK_64BIT; 554 555 *flags &= ~MASK_RVE; 556 if (subset_list->lookup ("e")) 557 *flags |= MASK_RVE; 558 559 *flags &= ~MASK_MUL; 560 if (subset_list->lookup ("m")) 561 *flags |= MASK_MUL; 562 563 *flags &= ~MASK_ATOMIC; 564 if (subset_list->lookup ("a")) 565 *flags |= MASK_ATOMIC; 566 567 *flags &= ~(MASK_HARD_FLOAT | MASK_DOUBLE_FLOAT); 568 if (subset_list->lookup ("f")) 569 *flags |= MASK_HARD_FLOAT; 570 571 if (subset_list->lookup ("d")) 572 *flags |= MASK_DOUBLE_FLOAT; 573 574 *flags &= ~MASK_RVC; 575 if (subset_list->lookup ("c")) 576 *flags |= MASK_RVC; 577 578 if (current_subset_list) 579 delete current_subset_list; 580 581 current_subset_list = subset_list; 582 } 583 584 /* Implement TARGET_HANDLE_OPTION. */ 585 586 static bool 587 riscv_handle_option (struct gcc_options *opts, 588 struct gcc_options *opts_set ATTRIBUTE_UNUSED, 589 const struct cl_decoded_option *decoded, 590 location_t loc) 591 { 592 switch (decoded->opt_index) 593 { 594 case OPT_march_: 595 riscv_parse_arch_string (decoded->arg, &opts->x_target_flags, loc); 596 return true; 597 598 default: 599 return true; 600 } 601 } 602 603 /* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */ 604 static const struct default_options riscv_option_optimization_table[] = 605 { 606 { OPT_LEVELS_1_PLUS, OPT_fsection_anchors, NULL, 1 }, 607 { OPT_LEVELS_2_PLUS, OPT_free, NULL, 1 }, 608 { OPT_LEVELS_NONE, 0, NULL, 0 } 609 }; 610 611 #undef TARGET_OPTION_OPTIMIZATION_TABLE 612 #define TARGET_OPTION_OPTIMIZATION_TABLE riscv_option_optimization_table 613 614 #undef TARGET_HANDLE_OPTION 615 #define TARGET_HANDLE_OPTION riscv_handle_option 616 617 struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER; 618