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 set_loc (location_t loc
) {
57 void update_settings (struct gcc_options
*opts
) const;
59 const char *m_raw_attr_str
;
60 bool parse_arch (const char *);
65 riscv_subset_list
*m_subset_list
;
67 const riscv_cpu_info
*m_cpu_info
;
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
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
}};
90 riscv_target_attr_parser::parse_arch (const char *str
)
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)
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
);
120 "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
);
142 if (m_subset_list
!= nullptr)
144 delete m_subset_list
;
145 m_subset_list
= nullptr;
150 /* Handle the ARCH_STR argument to the arch= target attribute. */
153 riscv_target_attr_parser::handle_arch (const char *str
)
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. */
164 riscv_target_attr_parser::handle_cpu (const char *str
)
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
);
174 error_at (m_loc
, "%<target()%> attribute: unknown CPU %qs", str
);
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
;
189 /* Handle the TUNE_STR argument to the tune= target attribute. */
192 riscv_target_attr_parser::handle_tune (const char *str
)
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);
201 error_at (m_loc
, "%<target()%> attribute: unknown TUNE %qs", str
);
211 riscv_target_attr_parser::update_settings (struct gcc_options
*opts
) const
214 riscv_set_arch_by_subset_list (m_subset_list
, opts
);
217 opts
->x_riscv_cpu_string
= m_cpu_info
->name
;
220 opts
->x_riscv_tune_string
= m_tune
;
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. */
232 riscv_process_one_target_attr (char *arg_str
,
234 riscv_target_attr_parser
&attr_parser
)
236 size_t len
= strlen (arg_str
);
240 error_at (loc
, "malformed %<target()%> attribute");
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
, '=');
254 "attribute %<target(\"%s\")%> does not accept an argument",
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)
269 return (&attr_parser
->*attr
.handler
) (arg
);
271 error_at (loc
, "Got unknown attribute %<target(\"%s\")%>", str_to_check
);
276 /* Count how many times the character C appears in
277 NULL-terminated string STR. */
280 num_occurences_in_str (char c
, char *str
)
282 unsigned int res
= 0;
294 /* Parse the tree in ARGS that contains the target attribute information
295 and update the global target options space. */
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
);
307 if (!riscv_process_target_attr (head
, loc
, opts
))
310 args
= TREE_CHAIN (args
);
316 if (TREE_CODE (args
) != STRING_CST
)
318 error_at (loc
, "attribute %<target%> argument not a string");
321 size_t len
= strlen (TREE_STRING_POINTER (args
));
323 /* No need to emit warning or error on empty string here, generic code already
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;
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
));
357 /* Apply settings from target attribute. */
358 attr_parser
.update_settings (opts
);
363 /* Implement TARGET_OPTION_VALID_ATTRIBUTE_P. This is used to
364 process attribute ((target ("..."))). */
367 riscv_option_valid_attribute_p (tree fndecl
, tree
, tree args
, int)
369 struct cl_target_option cur_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
);
381 riscv_override_options_internal (&global_options
);
383 = build_target_option_node (&global_options
, &global_options_set
);
390 DECL_FUNCTION_SPECIFIC_TARGET (fndecl
) = new_target
;
393 cl_target_option_restore (&global_options
, &global_options_set
, &cur_target
);