vect: Add missed opcodes in vect_get_smallest_scalar_type [PR115228]
[official-gcc.git] / gcc / config / riscv / riscv-target-attr.cc
blob1645a66921775018f683c3c52c8bac3c1168dcac
1 /* Subroutines used for parsing target attribute for RISC-V.
2 Copyright (C) 2023-2024 Free Software Foundation, Inc.
4 This file is part of GCC.
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.
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.
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/>. */
20 #define IN_TARGET_CODE 1
22 #define INCLUDE_MEMORY
23 #define INCLUDE_STRING
24 #include "config.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "target.h"
28 #include "tree.h"
29 #include "tm_p.h"
30 #include "diagnostic.h"
31 #include "opts.h"
32 #include "riscv-subset.h"
34 namespace {
35 class riscv_target_attr_parser
37 public:
38 riscv_target_attr_parser (location_t loc)
39 : m_found_arch_p (false)
40 , m_found_tune_p (false)
41 , m_found_cpu_p (false)
42 , m_subset_list (nullptr)
43 , m_loc (loc)
44 , m_cpu_info (nullptr)
45 , m_tune (nullptr)
49 bool handle_arch (const char *);
50 bool handle_cpu (const char *);
51 bool handle_tune (const char *);
53 void update_settings (struct gcc_options *opts) const;
54 private:
55 const char *m_raw_attr_str;
56 bool parse_arch (const char *);
58 bool m_found_arch_p;
59 bool m_found_tune_p;
60 bool m_found_cpu_p;
61 riscv_subset_list *m_subset_list;
62 location_t m_loc;
63 const riscv_cpu_info *m_cpu_info;
64 const char *m_tune;
68 /* All the information needed to handle a target attribute.
69 NAME is the name of the attribute.
70 HANDLER is the function that takes the attribute string as an argument. */
72 struct riscv_attribute_info
74 const char *name;
75 bool (riscv_target_attr_parser::*handler) (const char *);
78 /* The target attributes that we support. */
80 static const struct riscv_attribute_info riscv_attributes[]
81 = {{"arch", &riscv_target_attr_parser::handle_arch},
82 {"cpu", &riscv_target_attr_parser::handle_cpu},
83 {"tune", &riscv_target_attr_parser::handle_tune}};
85 bool
86 riscv_target_attr_parser::parse_arch (const char *str)
88 if (m_subset_list)
89 delete m_subset_list;
90 /* Check if it's setting full arch string. */
91 if (strncmp ("rv", str, strlen ("rv")) == 0)
93 m_subset_list = riscv_subset_list::parse (str, m_loc);
95 if (m_subset_list == nullptr)
96 goto fail;
98 return true;
100 else
102 /* Parsing the extension list like "+<ext>[,+<ext>]*". */
103 size_t len = strlen (str);
104 std::unique_ptr<char[]> buf (new char[len+1]);
105 char *str_to_check = buf.get ();
106 strcpy (str_to_check, str);
107 const char *token = strtok_r (str_to_check, ",", &str_to_check);
108 const char *local_arch_str = global_options.x_riscv_arch_string;
109 m_subset_list = local_arch_str
110 ? riscv_subset_list::parse (local_arch_str, m_loc)
111 : riscv_cmdline_subset_list ()->clone ();
112 m_subset_list->set_loc (m_loc);
113 m_subset_list->set_allow_adding_dup (true);
115 while (token)
117 if (token[0] != '+')
119 error_at (
120 m_loc,
121 "unexpected arch for %<target()%> attribute: must start "
122 "with + or rv");
123 goto fail;
126 const char *result = m_subset_list->parse_single_ext (token + 1);
127 /* Check parse_single_ext has consume all string. */
128 if (*result != '\0')
130 error_at (
131 m_loc,
132 "unexpected arch for %<target()%> attribute: bad "
133 "string found %<%s%>", token);
134 goto fail;
137 token = strtok_r (NULL, ",", &str_to_check);
140 m_subset_list->set_allow_adding_dup (false);
141 m_subset_list->finalize ();
142 return true;
144 fail:
145 if (m_subset_list != nullptr)
147 delete m_subset_list;
148 m_subset_list = nullptr;
150 return false;
153 /* Handle the ARCH_STR argument to the arch= target attribute. */
155 bool
156 riscv_target_attr_parser::handle_arch (const char *str)
158 if (m_found_arch_p)
159 error_at (m_loc, "%<target()%> attribute: arch appears more than once");
160 m_found_arch_p = true;
161 return parse_arch (str);
164 /* Handle the CPU_STR argument to the cpu= target attribute. */
166 bool
167 riscv_target_attr_parser::handle_cpu (const char *str)
169 if (m_found_cpu_p)
170 error_at (m_loc, "%<target()%> attribute: cpu appears more than once");
172 m_found_cpu_p = true;
173 const riscv_cpu_info *cpu_info = riscv_find_cpu (str);
175 if (!cpu_info)
177 error_at (m_loc, "%<target()%> attribute: unknown CPU %qs", str);
178 return false;
181 if (m_subset_list == nullptr)
183 const char *arch_str = cpu_info->arch;
184 m_subset_list = riscv_subset_list::parse (arch_str, m_loc);
185 gcc_assert (m_subset_list);
188 m_cpu_info = cpu_info;
189 return true;
192 /* Handle the TUNE_STR argument to the tune= target attribute. */
194 bool
195 riscv_target_attr_parser::handle_tune (const char *str)
197 if (m_found_tune_p)
198 error_at (m_loc, "%<target()%> attribute: tune appears more than once");
199 m_found_tune_p = true;
200 const struct riscv_tune_info *tune = riscv_parse_tune (str, true);
202 if (tune == nullptr)
204 error_at (m_loc, "%<target()%> attribute: unknown TUNE %qs", str);
205 return false;
208 m_tune = tune->name;
210 return true;
213 void
214 riscv_target_attr_parser::update_settings (struct gcc_options *opts) const
216 if (m_subset_list)
218 std::string local_arch = m_subset_list->to_string (true);
219 const char* local_arch_str = local_arch.c_str ();
220 struct cl_target_option *default_opts
221 = TREE_TARGET_OPTION (target_option_default_node);
222 if (opts->x_riscv_arch_string != default_opts->x_riscv_arch_string)
223 free (CONST_CAST (void *, (const void *) opts->x_riscv_arch_string));
224 opts->x_riscv_arch_string = xstrdup (local_arch_str);
226 riscv_set_arch_by_subset_list (m_subset_list, opts);
229 if (m_cpu_info)
230 opts->x_riscv_cpu_string = m_cpu_info->name;
232 if (m_tune)
233 opts->x_riscv_tune_string = m_tune;
234 else
236 if (m_cpu_info)
237 opts->x_riscv_tune_string = m_cpu_info->tune;
241 /* Parse ARG_STR which contains the definition of one target attribute.
242 Show appropriate errors if any or return true if the attribute is valid. */
244 static bool
245 riscv_process_one_target_attr (char *arg_str,
246 location_t loc,
247 riscv_target_attr_parser &attr_parser)
249 size_t len = strlen (arg_str);
251 if (len == 0)
253 error_at (loc, "malformed %<target()%> attribute");
254 return false;
257 std::unique_ptr<char[]> buf (new char[len+1]);
258 char *str_to_check = buf.get();
259 strcpy (str_to_check, arg_str);
261 char *arg = strchr (str_to_check, '=');
263 if (!arg)
265 error_at (
266 loc,
267 "attribute %<target(\"%s\")%> does not accept an argument",
268 str_to_check);
269 return false;
272 arg[0] = '\0';
273 ++arg;
274 for (const auto &attr : riscv_attributes)
276 /* If the names don't match up, or the user has given an argument
277 to an attribute that doesn't accept one, or didn't give an argument
278 to an attribute that expects one, fail to match. */
279 if (strncmp (str_to_check, attr.name, strlen (attr.name)) != 0)
280 continue;
282 return (&attr_parser->*attr.handler) (arg);
285 error_at (loc, "Got unknown attribute %<target(\"%s\")%>", str_to_check);
286 return false;
289 /* Count how many times the character C appears in
290 NULL-terminated string STR. */
292 static unsigned int
293 num_occurences_in_str (char c, char *str)
295 unsigned int res = 0;
296 while (*str != '\0')
298 if (*str == c)
299 res++;
301 str++;
304 return res;
307 /* Parse the tree in ARGS that contains the target attribute information
308 and update the global target options space. */
310 static bool
311 riscv_process_target_attr (tree args, location_t loc)
313 if (TREE_CODE (args) == TREE_LIST)
317 tree head = TREE_VALUE (args);
318 if (head)
320 if (!riscv_process_target_attr (head, loc))
321 return false;
323 args = TREE_CHAIN (args);
324 } while (args);
326 return true;
329 if (TREE_CODE (args) != STRING_CST)
331 error_at (loc, "attribute %<target%> argument not a string");
332 return false;
335 size_t len = strlen (TREE_STRING_POINTER (args));
337 /* No need to emit warning or error on empty string here, generic code already
338 handle this case. */
339 if (len == 0)
341 return false;
344 std::unique_ptr<char[]> buf (new char[len+1]);
345 char *str_to_check = buf.get ();
346 strcpy (str_to_check, TREE_STRING_POINTER (args));
348 /* Used to catch empty spaces between semi-colons i.e.
349 attribute ((target ("attr1;;attr2"))). */
350 unsigned int num_semicolons = num_occurences_in_str (';', str_to_check);
352 /* Handle multiple target attributes separated by ';'. */
353 char *token = strtok_r (str_to_check, ";", &str_to_check);
355 riscv_target_attr_parser attr_parser (loc);
356 unsigned int num_attrs = 0;
357 while (token)
359 num_attrs++;
360 if (!riscv_process_one_target_attr (token, loc, attr_parser))
361 return false;
363 token = strtok_r (NULL, ";", &str_to_check);
366 if (num_attrs != num_semicolons + 1)
368 error_at (loc, "malformed %<target(\"%s\")%> attribute",
369 TREE_STRING_POINTER (args));
370 return false;
373 /* Apply settings from target attribute. */
374 attr_parser.update_settings (&global_options);
376 return true;
379 /* Implement TARGET_OPTION_VALID_ATTRIBUTE_P.
380 This is used to process attribute ((target ("..."))).
381 Note, that riscv_set_current_function() has not been called before,
382 so we need must not mess with the current global_options, which
383 likely belong to another function. */
385 bool
386 riscv_option_valid_attribute_p (tree fndecl, tree, tree args, int)
388 struct cl_target_option cur_target;
389 bool ret;
390 tree new_target;
391 tree existing_target = DECL_FUNCTION_SPECIFIC_TARGET (fndecl);
392 location_t loc = DECL_SOURCE_LOCATION (fndecl);
394 /* Save the current target options to restore at the end. */
395 cl_target_option_save (&cur_target, &global_options, &global_options_set);
397 /* If fndecl already has some target attributes applied to it, unpack
398 them so that we add this attribute on top of them, rather than
399 overwriting them. */
400 if (existing_target)
402 struct cl_target_option *existing_options
403 = TREE_TARGET_OPTION (existing_target);
405 if (existing_options)
406 cl_target_option_restore (&global_options, &global_options_set,
407 existing_options);
409 else
410 cl_target_option_restore (&global_options, &global_options_set,
411 TREE_TARGET_OPTION (target_option_default_node));
413 /* Now we can parse the attributes and set &global_options accordingly. */
414 ret = riscv_process_target_attr (args, loc);
415 if (ret)
417 riscv_override_options_internal (&global_options);
418 new_target = build_target_option_node (&global_options,
419 &global_options_set);
420 DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target;
423 /* Restore current target options to original state. */
424 cl_target_option_restore (&global_options, &global_options_set, &cur_target);
425 return ret;