Add hppa*-*-hpux* to targets which do not support split DWARF
[official-gcc.git] / gcc / config / riscv / riscv-target-attr.cc
blob9dbb78f28cc0bd1be81bdc53c398b0b9d65683bf
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 set_loc (location_t loc) {
54 m_loc = loc;
57 void update_settings (struct gcc_options *opts) const;
58 private:
59 const char *m_raw_attr_str;
60 bool parse_arch (const char *);
62 bool m_found_arch_p;
63 bool m_found_tune_p;
64 bool m_found_cpu_p;
65 riscv_subset_list *m_subset_list;
66 location_t m_loc;
67 const riscv_cpu_info *m_cpu_info;
68 const char *m_tune;
72 /* All the information needed to handle a target attribute.
73 NAME is the name of the attribute.
74 HANDLER is the function that takes the attribute string as an argument. */
76 struct riscv_attribute_info
78 const char *name;
79 bool (riscv_target_attr_parser::*handler) (const char *);
82 /* The target attributes that we support. */
84 static const struct riscv_attribute_info riscv_attributes[]
85 = {{"arch", &riscv_target_attr_parser::handle_arch},
86 {"cpu", &riscv_target_attr_parser::handle_cpu},
87 {"tune", &riscv_target_attr_parser::handle_tune}};
89 bool
90 riscv_target_attr_parser::parse_arch (const char *str)
92 if (m_subset_list)
93 delete m_subset_list;
94 /* Check if it's setting full arch string. */
95 if (strncmp ("rv", str, strlen ("rv")) == 0)
97 m_subset_list = riscv_subset_list::parse (str, location_t ());
99 if (m_subset_list == nullptr)
100 goto fail;
102 return true;
104 else
106 /* Parsing the extension list like "+<ext>[,+<ext>]*". */
107 size_t len = strlen (str);
108 std::unique_ptr<char[]> buf (new char[len]);
109 char *str_to_check = buf.get ();
110 strcpy (str_to_check, str);
111 const char *token = strtok_r (str_to_check, ",", &str_to_check);
112 m_subset_list = riscv_current_subset_list ()->clone ();
113 m_subset_list->set_loc (m_loc);
114 while (token)
116 if (token[0] != '+')
118 error_at (
119 m_loc,
120 "unexpected arch for %<target()%> attribute: must start "
121 "with + or rv");
122 goto fail;
124 else
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);
139 return true;
141 fail:
142 if (m_subset_list != nullptr)
144 delete m_subset_list;
145 m_subset_list = nullptr;
147 return false;
150 /* Handle the ARCH_STR argument to the arch= target attribute. */
152 bool
153 riscv_target_attr_parser::handle_arch (const char *str)
155 if (m_found_arch_p)
156 error_at (m_loc, "%<target()%> attribute: arch appears more than once");
157 m_found_arch_p = true;
158 return parse_arch (str);
161 /* Handle the CPU_STR argument to the cpu= target attribute. */
163 bool
164 riscv_target_attr_parser::handle_cpu (const char *str)
166 if (m_found_cpu_p)
167 error_at (m_loc, "%<target()%> attribute: cpu appears more than once");
169 m_found_cpu_p = true;
170 const riscv_cpu_info *cpu_info = riscv_find_cpu (str);
172 if (!cpu_info)
174 error_at (m_loc, "%<target()%> attribute: unknown CPU %qs", str);
175 return false;
178 if (m_subset_list == nullptr)
180 const char *arch_str = cpu_info->arch;
181 m_subset_list = riscv_subset_list::parse (arch_str, m_loc);
182 gcc_assert (m_subset_list);
185 m_cpu_info = cpu_info;
186 return true;
189 /* Handle the TUNE_STR argument to the tune= target attribute. */
191 bool
192 riscv_target_attr_parser::handle_tune (const char *str)
194 if (m_found_tune_p)
195 error_at (m_loc, "%<target()%> attribute: tune appears more than once");
196 m_found_tune_p = true;
197 const struct riscv_tune_info *tune = riscv_parse_tune (str, true);
199 if (tune == nullptr)
201 error_at (m_loc, "%<target()%> attribute: unknown TUNE %qs", str);
202 return false;
205 m_tune = tune->name;
207 return true;
210 void
211 riscv_target_attr_parser::update_settings (struct gcc_options *opts) const
213 if (m_subset_list)
214 riscv_set_arch_by_subset_list (m_subset_list, opts);
216 if (m_cpu_info)
217 opts->x_riscv_cpu_string = m_cpu_info->name;
219 if (m_tune)
220 opts->x_riscv_tune_string = m_tune;
221 else
223 if (m_cpu_info)
224 opts->x_riscv_tune_string = m_cpu_info->tune;
228 /* Parse ARG_STR which contains the definition of one target attribute.
229 Show appropriate errors if any or return true if the attribute is valid. */
231 static bool
232 riscv_process_one_target_attr (char *arg_str,
233 location_t loc,
234 riscv_target_attr_parser &attr_parser)
236 size_t len = strlen (arg_str);
238 if (len == 0)
240 error_at (loc, "malformed %<target()%> attribute");
241 return false;
244 std::unique_ptr<char[]> buf (new char[len]);
245 char *str_to_check = buf.get();
246 strcpy (str_to_check, arg_str);
248 char *arg = strchr (str_to_check, '=');
250 if (!arg)
252 error_at (
253 loc,
254 "attribute %<target(\"%s\")%> does not accept an argument",
255 str_to_check);
256 return false;
259 arg[0] = '\0';
260 ++arg;
261 for (const auto &attr : riscv_attributes)
263 /* If the names don't match up, or the user has given an argument
264 to an attribute that doesn't accept one, or didn't give an argument
265 to an attribute that expects one, fail to match. */
266 if (strncmp (str_to_check, attr.name, strlen (attr.name)) != 0)
267 continue;
269 return (&attr_parser->*attr.handler) (arg);
271 error_at (loc, "Got unknown attribute %<target(\"%s\")%>", str_to_check);
273 return false;
276 /* Count how many times the character C appears in
277 NULL-terminated string STR. */
279 static unsigned int
280 num_occurences_in_str (char c, char *str)
282 unsigned int res = 0;
283 while (*str != '\0')
285 if (*str == c)
286 res++;
288 str++;
291 return res;
294 /* Parse the tree in ARGS that contains the target attribute information
295 and update the global target options space. */
297 static bool
298 riscv_process_target_attr (tree args, location_t loc, struct gcc_options *opts)
300 if (TREE_CODE (args) == TREE_LIST)
304 tree head = TREE_VALUE (args);
305 if (head)
307 if (!riscv_process_target_attr (head, loc, opts))
308 return false;
310 args = TREE_CHAIN (args);
311 } while (args);
313 return true;
316 if (TREE_CODE (args) != STRING_CST)
318 error_at (loc, "attribute %<target%> argument not a string");
319 return false;
321 size_t len = strlen (TREE_STRING_POINTER (args));
323 /* No need to emit warning or error on empty string here, generic code already
324 handle this case. */
325 if (len == 0)
327 return false;
330 std::unique_ptr<char[]> buf (new char[len]);
331 char *str_to_check = buf.get ();
332 strcpy (str_to_check, TREE_STRING_POINTER (args));
334 /* Used to catch empty spaces between commas i.e.
335 attribute ((target ("attr1;;attr2"))). */
336 unsigned int num_commas = num_occurences_in_str (';', str_to_check);
338 /* Handle multiple target attributes separated by ','. */
339 char *token = strtok_r (str_to_check, ";", &str_to_check);
341 riscv_target_attr_parser attr_parser (loc);
342 unsigned int num_attrs = 0;
343 while (token)
345 num_attrs++;
346 riscv_process_one_target_attr (token, loc, attr_parser);
347 token = strtok_r (NULL, ";", &str_to_check);
350 if (num_attrs != num_commas + 1)
352 error_at (loc, "malformed %<target(\"%s\")%> attribute",
353 TREE_STRING_POINTER (args));
354 return false;
357 /* Apply settings from target attribute. */
358 attr_parser.update_settings (opts);
360 return true;
363 /* Implement TARGET_OPTION_VALID_ATTRIBUTE_P. This is used to
364 process attribute ((target ("..."))). */
366 bool
367 riscv_option_valid_attribute_p (tree fndecl, tree, tree args, int)
369 struct cl_target_option cur_target;
370 bool ret;
371 tree new_target;
372 location_t loc = DECL_SOURCE_LOCATION (fndecl);
374 /* Save the current target options to restore at the end. */
375 cl_target_option_save (&cur_target, &global_options, &global_options_set);
377 ret = riscv_process_target_attr (args, loc, &global_options);
379 if (ret)
381 riscv_override_options_internal (&global_options);
382 new_target
383 = build_target_option_node (&global_options, &global_options_set);
385 else
386 new_target = NULL;
388 if (fndecl && ret)
390 DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target;
393 cl_target_option_restore (&global_options, &global_options_set, &cur_target);
394 return ret;