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)
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
26 #include "coretypes.h"
30 #include "diagnostic.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
55 enum loongarch_attr_opt_type attr_type
;
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____
}
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
;
83 case OPT_mstrict_align
:
85 opts
->x_target_flags
|= MASK_STRICT_ALIGN
;
87 opts
->x_target_flags
&= ~MASK_STRICT_ALIGN
;
91 opts
->x_la_opt_cmodel
= val
;
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
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;
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
111 opts
->x_str_align_functions
= NULL
;
112 opts
->x_str_align_loops
= NULL
;
113 opts
->x_str_align_jumps
= NULL
;
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
;
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
);
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. */
136 loongarch_process_one_target_attr (char *arg_str
, location_t loc
)
140 size_t len
= strlen (arg_str
);
144 error_at (loc
, "malformed %<target()%> pragma or attribute");
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-"))
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". */
165 const struct loongarch_attribute_info
*p_attr
;
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)
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
);
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
);
203 /* Use the option setting machinery to set an option to an enum. */
204 case loongarch_attr_enum
:
209 struct cl_decoded_option decoded
;
210 valid
= opt_enum_arg_to_value (p_attr
->opt_num
, arg
,
213 decoded
.opt_index
= p_attr
->opt_num
;
214 decoded
.value
= value
;
217 loongarch_handle_option (&global_options
,
219 &decoded
, input_location
);
221 error_at (loc
, "pragma or attribute %<target(\"%s=%s\")%> is "
222 "not valid", str_to_check
, arg
);
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
);
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. */
246 error_at (loc
, "attribute %<target%> argument %qs is unknown",
252 /* Count how many times the character C appears in
253 NULL-terminated string STR. */
256 num_occurences_in_str (char c
, char *str
)
258 unsigned int res
= 0;
270 /* Parse the tree in ARGS that contains the target attribute information
271 and update the global target options space. */
274 loongarch_process_target_attr (tree args
, tree fndecl
)
277 = fndecl
== NULL
? UNKNOWN_LOCATION
: DECL_SOURCE_LOCATION (fndecl
);
279 if (TREE_CODE (args
) == TREE_LIST
)
283 tree head
= TREE_VALUE (args
);
286 if (!loongarch_process_target_attr (head
, fndecl
))
289 args
= TREE_CHAIN (args
);
295 if (TREE_CODE (args
) != STRING_CST
)
297 error_at (loc
, "attribute %<target%> argument not a string");
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);
309 error_at (loc
, "malformed %<target()%> pragma or attribute");
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;
324 if (!loongarch_process_one_target_attr (token
, loc
))
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
));
340 /* Implement TARGET_OPTION_VALID_ATTRIBUTE_P. This is used to
341 process attribute ((target ("..."))). */
344 loongarch_option_valid_attribute_p (tree fndecl
, tree
, tree args
, int)
346 struct cl_target_option cur_target
;
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
;
362 tree func_optimize
= DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl
);
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
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
,
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. */
397 loongarch_option_override_internal (&la_target
,
399 &global_options_set
);
400 new_target
= build_target_option_node (&global_options
,
401 &global_options_set
);
406 new_optimize
= build_optimization_node (&global_options
,
407 &global_options_set
);
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
));
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. */
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. */
436 if (!loongarch_process_target_attr (args
, NULL
))
439 loongarch_option_override_internal (&la_target
,
441 &global_options_set
);
444 /* args is NULL, restore to the state described in pop_target. */
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. */
460 loongarch_save_restore_target_globals (pop_target
);
465 /* Implement REGISTER_TARGET_PRAGMAS. */
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
;