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 
xlen()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 
riscv_subset_t()97 riscv_subset_t::riscv_subset_t ()
98   : name (), major_version (0), minor_version (0), next (NULL)
99 {
100 }
101 
riscv_subset_list(const char * arch,location_t loc)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 
~riscv_subset_list()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
add(const char * subset,int major_version,int minor_version)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
to_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 *
lookup(const char * subset,int major_version,int minor_version)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 *
riscv_supported_std_ext(void)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 *
parsing_subset_version(const char * p,unsigned * major_version,unsigned * minor_version,unsigned default_major_version,unsigned default_minor_version,bool std_ext_p)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 *
parse_std_ext(const char * p)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 *
parse_sv_or_non_std_ext(const char * p,const char * ext_type,const char * ext_type_str)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 *
parse(const char * arch,location_t loc)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
riscv_arch_str()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
riscv_parse_arch_string(const char * isa,int * flags,location_t loc)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
riscv_handle_option(struct gcc_options * opts,struct gcc_options * opts_set ATTRIBUTE_UNUSED,const struct cl_decoded_option * decoded,location_t loc)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