[PR testsuite/116860] Testsuite adjustment for recently added tests
[official-gcc.git] / gcc / config / loongarch / loongarch-target-attr.cc
blobcee7031ca1e76addfa31c8b163eade4fc6620323
1 /* Subroutines used for LoongArch code generation.
2 Copyright (C) 2025 Free Software Foundation, Inc.
3 Contributed by Loongson Ltd.
4 Based on AArch64 target for GNU compiler.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 #define IN_TARGET_CODE 1
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"
33 /* Enum describing the various ways we can handle attributes.
34 In many cases we can reuse the generic option handling machinery. */
36 enum loongarch_attr_opt_type
38 loongarch_attr_mask, /* Attribute should set a bit in target_flags. */
39 loongarch_attr_enum, /* Attribute sets an enum variable. */
40 loongarch_attr_bool /* Attribute sets or unsets a boolean variable. */
43 /* All the information needed to handle a target attribute.
44 NAME is the name of the attribute.
45 ATTR_TYPE specifies the type of behavior of the attribute as described
46 in the definition of enum loongarch_attr_opt_type.
47 ALLOW_NEG is true if the attribute supports a "no-" form.
48 OPT_NUM is the enum specifying the option that the attribute modifies.
49 This is needed for attributes that mirror the behavior of a command-line
50 option, that is it has ATTR_TYPE loongarch_attr_mask. */
52 struct loongarch_attribute_info
54 const char *name;
55 enum loongarch_attr_opt_type attr_type;
56 bool allow_neg;
57 enum opt_code opt_num;
59 /* The target attributes that we support. */
61 static const struct loongarch_attribute_info loongarch_attributes[] =
63 { "strict-align", loongarch_attr_mask, true, OPT_mstrict_align },
64 { "cmodel", loongarch_attr_enum, false, OPT_mcmodel_ },
65 { "arch", loongarch_attr_enum, false, OPT_march_ },
66 { "tune", loongarch_attr_enum, false, OPT_mtune_ },
67 { "lsx", loongarch_attr_bool, true, OPT_mlsx },
68 { "lasx", loongarch_attr_bool, true, OPT_mlasx },
69 { NULL, loongarch_attr_bool, false, OPT____ }
72 bool
73 loongarch_handle_option (struct gcc_options *opts,
74 struct gcc_options *opts_set ATTRIBUTE_UNUSED,
75 const struct cl_decoded_option *decoded,
76 location_t loc ATTRIBUTE_UNUSED)
78 size_t code = decoded->opt_index;
79 int val = decoded->value;
81 switch (code)
83 case OPT_mstrict_align:
84 if (val)
85 opts->x_target_flags |= MASK_STRICT_ALIGN;
86 else
87 opts->x_target_flags &= ~MASK_STRICT_ALIGN;
88 return true;
90 case OPT_mcmodel_:
91 opts->x_la_opt_cmodel = val;
92 return true;
94 case OPT_march_:
95 opts->x_la_opt_cpu_arch = val;
97 /* Set these variables to the initial values so that they can be reset
98 in the loongarch_config_target function according to the ARCH
99 settings. */
100 opts->x_la_opt_simd = M_OPT_UNSET;
101 opts->x_la_opt_fpu = M_OPT_UNSET;
102 opts->x_la_isa_evolution = 0;
103 return true;
105 case OPT_mtune_:
106 opts->x_la_opt_cpu_tune = val;
108 /* Set these variables to the initial values so that they can be reset
109 in the loongarch_target_option_override function according to the TUNE
110 settings. */
111 opts->x_str_align_functions = NULL;
112 opts->x_str_align_loops = NULL;
113 opts->x_str_align_jumps = NULL;
114 return true;
116 case OPT_mlsx:
117 opts->x_la_opt_simd = val ? (la_opt_simd == ISA_EXT_SIMD_LASX
118 ? ISA_EXT_SIMD_LASX : ISA_EXT_SIMD_LSX) : ISA_EXT_NONE;
119 return true;
121 case OPT_mlasx:
122 opts->x_la_opt_simd = val ? ISA_EXT_SIMD_LASX
123 : (la_opt_simd == ISA_EXT_SIMD_LASX || la_opt_simd == ISA_EXT_SIMD_LSX
124 ? ISA_EXT_SIMD_LSX : ISA_EXT_NONE);
125 return true;
127 default:
128 return true;
132 /* Parse ARG_STR which contains the definition of one target attribute.
133 Show appropriate errors if any or return true if the attribute is valid. */
135 static bool
136 loongarch_process_one_target_attr (char *arg_str, location_t loc)
138 bool invert = false;
140 size_t len = strlen (arg_str);
142 if (len == 0)
144 error_at (loc, "malformed %<target()%> pragma or attribute");
145 return false;
148 char *str_to_check = (char *) alloca (len + 1);
149 strcpy (str_to_check, arg_str);
151 if (len > 3 && startswith (str_to_check, "no-"))
153 invert = true;
154 str_to_check += 3;
156 char *arg = strchr (str_to_check, '=');
158 /* If we found opt=foo then terminate STR_TO_CHECK at the '='
159 and point ARG to "foo". */
160 if (arg)
162 *arg = '\0';
163 arg++;
165 const struct loongarch_attribute_info *p_attr;
166 bool found = false;
167 for (p_attr = loongarch_attributes; p_attr->name; p_attr++)
169 /* If the names don't match up, or the user has given an argument
170 to an attribute that doesn't accept one, or didn't give an argument
171 to an attribute that expects one, fail to match. */
172 if (strcmp (str_to_check, p_attr->name) != 0)
173 continue;
175 found = true;
177 /* If the name matches but the attribute does not allow "no-" versions
178 then we can't match. */
179 if (invert && !p_attr->allow_neg)
181 error_at (loc, "pragma or attribute %<target(\"%s\")%> does not "
182 "allow a negated form", str_to_check);
183 return false;
186 switch (p_attr->attr_type)
188 /* Either set or unset a boolean option. */
189 case loongarch_attr_mask:
191 struct cl_decoded_option decoded;
193 /* We only need to specify the option number.
194 loongarch_handle_option will know which mask to apply. */
195 decoded.opt_index = p_attr->opt_num;
196 decoded.value = !invert;
198 loongarch_handle_option (&global_options, &global_options_set,
199 &decoded, input_location);
200 break;
203 /* Use the option setting machinery to set an option to an enum. */
204 case loongarch_attr_enum:
206 gcc_assert (arg);
207 bool valid;
208 int value;
209 struct cl_decoded_option decoded;
210 valid = opt_enum_arg_to_value (p_attr->opt_num, arg,
211 &value, CL_TARGET);
213 decoded.opt_index = p_attr->opt_num;
214 decoded.value = value;
216 if (valid)
217 loongarch_handle_option (&global_options,
218 &global_options_set,
219 &decoded, input_location);
220 else
221 error_at (loc, "pragma or attribute %<target(\"%s=%s\")%> is "
222 "not valid", str_to_check, arg);
223 break;
226 /* Either set or unset a boolean option. */
227 case loongarch_attr_bool:
229 struct cl_decoded_option decoded;
231 generate_option (p_attr->opt_num, NULL, !invert,
232 CL_TARGET, &decoded);
233 loongarch_handle_option (&global_options, &global_options_set,
234 &decoded, input_location);
235 break;
237 default:
238 gcc_unreachable ();
242 /* If we reached here we either have found an attribute and validated
243 it or didn't match any. If we matched an attribute but its arguments
244 were malformed we will have returned false already. */
245 if (!found)
246 error_at (loc, "attribute %<target%> argument %qs is unknown",
247 str_to_check);
249 return found;
252 /* Count how many times the character C appears in
253 NULL-terminated string STR. */
255 static unsigned int
256 num_occurences_in_str (char c, char *str)
258 unsigned int res = 0;
259 while (*str != '\0')
261 if (*str == c)
262 res++;
264 str++;
267 return res;
270 /* Parse the tree in ARGS that contains the target attribute information
271 and update the global target options space. */
273 bool
274 loongarch_process_target_attr (tree args, tree fndecl)
276 location_t loc
277 = fndecl == NULL ? UNKNOWN_LOCATION : DECL_SOURCE_LOCATION (fndecl);
279 if (TREE_CODE (args) == TREE_LIST)
283 tree head = TREE_VALUE (args);
284 if (head)
286 if (!loongarch_process_target_attr (head, fndecl))
287 return false;
289 args = TREE_CHAIN (args);
290 } while (args);
292 return true;
295 if (TREE_CODE (args) != STRING_CST)
297 error_at (loc, "attribute %<target%> argument not a string");
298 return false;
301 size_t len = strlen (TREE_STRING_POINTER (args));
302 auto_vec<char, 32> buffer;
303 buffer.safe_grow (len + 1);
304 char *str_to_check = buffer.address ();
305 memcpy (str_to_check, TREE_STRING_POINTER (args), len + 1);
307 if (len == 0)
309 error_at (loc, "malformed %<target()%> pragma or attribute");
310 return false;
313 /* Used to catch empty spaces between commas i.e.
314 attribute ((target ("attr1,,attr2"))). */
315 unsigned int num_commas = num_occurences_in_str (',', str_to_check);
317 /* Handle multiple target attributes separated by ','. */
318 char *token = strtok_r (str_to_check, ",", &str_to_check);
320 unsigned int num_attrs = 0;
321 while (token)
323 num_attrs++;
324 if (!loongarch_process_one_target_attr (token, loc))
325 return false;
327 token = strtok_r (NULL, ",", &str_to_check);
330 if (num_attrs != num_commas + 1)
332 error_at (loc, "malformed %<target(\"%s\")%> pragma or attribute",
333 TREE_STRING_POINTER (args));
334 return false;
337 return true;
340 /* Implement TARGET_OPTION_VALID_ATTRIBUTE_P. This is used to
341 process attribute ((target ("..."))). */
343 bool
344 loongarch_option_valid_attribute_p (tree fndecl, tree, tree args, int)
346 struct cl_target_option cur_target;
347 bool ret;
348 tree old_optimize;
349 tree new_target, new_optimize;
350 tree existing_target = DECL_FUNCTION_SPECIFIC_TARGET (fndecl);
352 /* If what we're processing is the current pragma string then the
353 target option node is already stored in target_option_current_node
354 by loongarch_pragma_target_parse in loongarch-target-attr.cc.
355 Use that to avoid having to re-parse the string. */
356 if (!existing_target && args == current_target_pragma)
358 DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = target_option_current_node;
359 return true;
362 tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
364 old_optimize
365 = build_optimization_node (&global_options, &global_options_set);
367 /* If the function changed the optimization levels as well as setting
368 target options, start with the optimizations specified. */
369 if (func_optimize && func_optimize != old_optimize)
370 cl_optimization_restore (&global_options, &global_options_set,
371 TREE_OPTIMIZATION (func_optimize));
373 /* Save the current target options to restore at the end. */
374 cl_target_option_save (&cur_target, &global_options, &global_options_set);
376 /* If fndecl already has some target attributes applied to it, unpack
377 them so that we add this attribute on top of them, rather than
378 overwriting them. */
379 if (existing_target)
381 struct cl_target_option *existing_options
382 = TREE_TARGET_OPTION (existing_target);
384 if (existing_options)
385 cl_target_option_restore (&global_options, &global_options_set,
386 existing_options);
388 else
389 cl_target_option_restore (&global_options, &global_options_set,
390 TREE_TARGET_OPTION (target_option_current_node));
392 ret = loongarch_process_target_attr (args, fndecl);
394 /* Set up any additional state. */
395 if (ret)
397 loongarch_option_override_internal (&la_target,
398 &global_options,
399 &global_options_set);
400 new_target = build_target_option_node (&global_options,
401 &global_options_set);
403 else
404 new_target = NULL;
406 new_optimize = build_optimization_node (&global_options,
407 &global_options_set);
409 if (fndecl && ret)
411 DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target;
413 if (old_optimize != new_optimize)
414 DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
417 cl_target_option_restore (&global_options, &global_options_set, &cur_target);
419 if (old_optimize != new_optimize)
420 cl_optimization_restore (&global_options, &global_options_set,
421 TREE_OPTIMIZATION (old_optimize));
422 return ret;
425 /* Hook to validate the current #pragma GCC target and set the state, and
426 update the macros based on what was changed. If ARGS is NULL, then
427 POP_TARGET is used to reset the options. */
429 static bool
430 loongarch_pragma_target_parse (tree args, tree pop_target)
432 /* If args is not NULL then process it and setup the target-specific
433 information that it specifies. */
434 if (args)
436 if (!loongarch_process_target_attr (args, NULL))
437 return false;
439 loongarch_option_override_internal (&la_target,
440 &global_options,
441 &global_options_set);
444 /* args is NULL, restore to the state described in pop_target. */
445 else
447 pop_target = pop_target ? pop_target : target_option_default_node;
448 cl_target_option_restore (&global_options, &global_options_set,
449 TREE_TARGET_OPTION (pop_target));
452 target_option_current_node
453 = build_target_option_node (&global_options, &global_options_set);
455 loongarch_reset_previous_fndecl ();
457 /* If we're popping or reseting make sure to update the globals so that
458 the optab availability predicates get recomputed. */
459 if (pop_target)
460 loongarch_save_restore_target_globals (pop_target);
462 return true;
465 /* Implement REGISTER_TARGET_PRAGMAS. */
467 void
468 loongarch_register_pragmas (void)
470 /* Update pragma hook to allow parsing #pragma GCC target. */
471 targetm.target_option.pragma_parse = loongarch_pragma_target_parse;