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)
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
26 #include "coretypes.h"
30 #include "diagnostic.h"
32 #include "riscv-subset.h"
35 class riscv_target_attr_parser
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)
44 , m_cpu_info (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;
55 const char *m_raw_attr_str
;
56 bool parse_arch (const char *);
61 riscv_subset_list
*m_subset_list
;
63 const riscv_cpu_info
*m_cpu_info
;
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
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
}};
86 riscv_target_attr_parser::parse_arch (const char *str
)
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)
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);
121 "unexpected arch for %<target()%> attribute: must start "
126 const char *result
= m_subset_list
->parse_single_ext (token
+ 1);
127 /* Check parse_single_ext has consume all string. */
132 "unexpected arch for %<target()%> attribute: bad "
133 "string found %<%s%>", token
);
137 token
= strtok_r (NULL
, ",", &str_to_check
);
140 m_subset_list
->set_allow_adding_dup (false);
141 m_subset_list
->finalize ();
145 if (m_subset_list
!= nullptr)
147 delete m_subset_list
;
148 m_subset_list
= nullptr;
153 /* Handle the ARCH_STR argument to the arch= target attribute. */
156 riscv_target_attr_parser::handle_arch (const char *str
)
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. */
167 riscv_target_attr_parser::handle_cpu (const char *str
)
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
);
177 error_at (m_loc
, "%<target()%> attribute: unknown CPU %qs", str
);
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
;
192 /* Handle the TUNE_STR argument to the tune= target attribute. */
195 riscv_target_attr_parser::handle_tune (const char *str
)
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);
204 error_at (m_loc
, "%<target()%> attribute: unknown TUNE %qs", str
);
214 riscv_target_attr_parser::update_settings (struct gcc_options
*opts
) const
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
);
230 opts
->x_riscv_cpu_string
= m_cpu_info
->name
;
233 opts
->x_riscv_tune_string
= m_tune
;
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. */
245 riscv_process_one_target_attr (char *arg_str
,
247 riscv_target_attr_parser
&attr_parser
)
249 size_t len
= strlen (arg_str
);
253 error_at (loc
, "malformed %<target()%> attribute");
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
, '=');
267 "attribute %<target(\"%s\")%> does not accept an argument",
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)
282 return (&attr_parser
->*attr
.handler
) (arg
);
285 error_at (loc
, "Got unknown attribute %<target(\"%s\")%>", str_to_check
);
289 /* Count how many times the character C appears in
290 NULL-terminated string STR. */
293 num_occurrences_in_str (char c
, char *str
)
295 unsigned int res
= 0;
307 /* Parse the tree in ARGS that contains the target attribute information
308 and update the global target options space. */
311 riscv_process_target_attr (tree args
, location_t loc
)
313 if (TREE_CODE (args
) == TREE_LIST
)
317 tree head
= TREE_VALUE (args
);
320 if (!riscv_process_target_attr (head
, loc
))
323 args
= TREE_CHAIN (args
);
329 if (TREE_CODE (args
) != STRING_CST
)
331 error_at (loc
, "attribute %<target%> argument not a string");
335 size_t len
= strlen (TREE_STRING_POINTER (args
));
337 /* No need to emit warning or error on empty string here, generic code already
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_occurrences_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;
360 if (!riscv_process_one_target_attr (token
, loc
, attr_parser
))
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
));
373 /* Apply settings from target attribute. */
374 attr_parser
.update_settings (&global_options
);
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. */
386 riscv_option_valid_attribute_p (tree fndecl
, tree
, tree args
, int)
388 struct cl_target_option cur_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
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
,
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
);
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
);