]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/common/config/riscv/riscv-common.c
Update copyright years.
[thirdparty/gcc.git] / gcc / common / config / riscv / riscv-common.c
CommitLineData
09cae750 1/* Common hooks for RISC-V.
8d9254fc 2 Copyright (C) 2016-2020 Free Software Foundation, Inc.
09cae750
PD
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 3, or (at your option)
9any later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING3. If not see
18<http://www.gnu.org/licenses/>. */
19
8e966210
KC
20#include <sstream>
21
22#define INCLUDE_STRING
09cae750
PD
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"
8e966210 32#include "config/riscv/riscv-protos.h"
09cae750 33
8e966210 34#define RISCV_DONT_CARE_VERSION -1
09cae750 35
8e966210
KC
36/* Subset info. */
37struct riscv_subset_t
09cae750 38{
8e966210 39 riscv_subset_t ();
09cae750 40
8e966210
KC
41 std::string name;
42 int major_version;
43 int minor_version;
44 struct riscv_subset_t *next;
45};
46
47/* Subset list. */
48class riscv_subset_list
49{
50private:
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
76public:
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
93static const char *riscv_supported_std_ext (void);
94
95static riscv_subset_list *current_subset_list = NULL;
96
97riscv_subset_t::riscv_subset_t ()
98 : name (), major_version (0), minor_version (0), next (NULL)
99{
100}
101
102riscv_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
107riscv_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)
09cae750 114 {
8e966210
KC
115 riscv_subset_t *next = item->next;
116 delete item;
117 item = next;
09cae750 118 }
8e966210 119}
09cae750 120
8e966210 121/* Add new subset to list. */
09cae750 122
8e966210
KC
123void
124riscv_subset_list::add (const char *subset, int major_version,
125 int minor_version)
126{
127 riscv_subset_t *s = new riscv_subset_t ();
09baee1a 128
8e966210
KC
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
145std::string
146riscv_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)
09cae750 155 {
8e966210
KC
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
174riscv_subset_t *
175riscv_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. */
09cae750 199
8e966210
KC
200static const char *
201riscv_supported_std_ext (void)
202{
203 return "mafdqlcbjtpvn";
204}
205
206/* Parsing subset version.
09baee1a 207
8e966210
KC
208 Return Value:
209 Points to the end of version
09cae750 210
8e966210
KC
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. */
09cae750 221
8e966210
KC
222const char *
223riscv_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')
09cae750 239 {
8e966210 240 np = *(p + 1);
09cae750 241
8e966210 242 if (!ISDIGIT (np))
09cae750 243 {
8e966210
KC
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 {
904f3daa
ML
253 error_at (m_loc, "%<-march=%s%>: Expect number "
254 "after %<%dp%>.", m_arch, version);
8e966210
KC
255 return NULL;
256 }
09cae750 257 }
8e966210
KC
258
259 major = version;
260 major_p = false;
261 version = 0;
09cae750 262 }
8e966210
KC
263 else if (ISDIGIT (*p))
264 version = (version * 10) + (*p - '0');
265 else
266 break;
09cae750 267 }
8e966210
KC
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
296const char *
297riscv_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)
09baee1a 308 {
8e966210
KC
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':
09baee1a 319 p++;
8e966210
KC
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);
09baee1a 324
8e966210 325 add ("e", major_version, minor_version);
09baee1a 326
8e966210 327 if (m_xlen > 32)
09baee1a 328 {
a3f9f006
ML
329 error_at (m_loc, "%<-march=%s%>: rv%de is not a valid base ISA",
330 m_arch, m_xlen);
8e966210 331 return NULL;
09baee1a 332 }
8e966210 333 break;
09baee1a 334
8e966210
KC
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);
09baee1a 342
8e966210
KC
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;
09baee1a 349
8e966210 350 default:
904f3daa
ML
351 error_at (m_loc, "%<-march=%s%>: first ISA subset must be %<e%>, "
352 "%<i%> or %<g%>", m_arch);
8e966210 353 return NULL;
09baee1a 354 }
8e966210
KC
355
356 while (*p)
09cae750 357 {
8e966210
KC
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)
904f3daa 378 error_at (m_loc, "%<-march=%s%>: unsupported ISA subset %<%c%>",
8e966210
KC
379 m_arch, *p);
380 else
381 error_at (m_loc,
a3f9f006 382 "%<-march=%s%>: ISA string is not in canonical order. "
904f3daa 383 "%<%c%>", m_arch, *p);
8e966210
KC
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);
09cae750 398 }
8e966210
KC
399 return p;
400}
09cae750 401
8e966210 402/* Parsing function for non-standard and supervisor extensions.
09cae750 403
8e966210
KC
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
412const char *
413riscv_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)
09cae750 422 {
8e966210
KC
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 {
a3f9f006 458 error_at (m_loc, "%<-march=%s%>: %s must separate with _",
8e966210
KC
459 m_arch, ext_type_str);
460 return NULL;
461 }
09cae750 462 }
8e966210
KC
463
464 return p;
465}
466
467/* Parsing arch string to subset list, return NULL if parsing failed. */
468
469riscv_subset_list *
470riscv_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 {
a3f9f006 486 error_at (loc, "%<-march=%s%>: ISA string must begin with rv32 or rv64",
8e966210
KC
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
285cf766
MB
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
8e966210
KC
523 return subset_list;
524
525fail:
526 delete subset_list;
527 return NULL;
528}
529
530/* Return the current arch string. */
531
532std::string
533riscv_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
542static void
543riscv_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
76d4accf
JW
574 *flags &= ~MASK_RVC;
575 if (subset_list->lookup ("c"))
576 *flags |= MASK_RVC;
577
8e966210
KC
578 if (current_subset_list)
579 delete current_subset_list;
580
581 current_subset_list = subset_list;
09cae750
PD
582}
583
584/* Implement TARGET_HANDLE_OPTION. */
585
586static bool
587riscv_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. */
604static const struct default_options riscv_option_optimization_table[] =
605 {
606 { OPT_LEVELS_1_PLUS, OPT_fsection_anchors, NULL, 1 },
09cae750
PD
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
617struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;