xref: /netbsd-src/external/gpl3/gcc/dist/gcc/config/aarch64/aarch64-c.cc (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 /* Target-specific code for C family languages.
2    Copyright (C) 2015-2022 Free Software Foundation, Inc.
3 
4    This file is part of GCC.
5 
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.
10 
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.
15 
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/>.  */
19 
20 #define IN_TARGET_CODE 1
21 
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "input.h"
27 #include "memmodel.h"
28 #include "tm_p.h"
29 #include "flags.h"
30 #include "c-family/c-common.h"
31 #include "cpplib.h"
32 #include "c-family/c-pragma.h"
33 #include "langhooks.h"
34 #include "target.h"
35 
36 
37 #define builtin_define(TXT) cpp_define (pfile, TXT)
38 #define builtin_assert(TXT) cpp_assert (pfile, TXT)
39 
40 
41 static void
aarch64_def_or_undef(bool def_p,const char * macro,cpp_reader * pfile)42 aarch64_def_or_undef (bool def_p, const char *macro, cpp_reader *pfile)
43 {
44   if (def_p)
45     cpp_define (pfile, macro);
46   else
47     cpp_undef (pfile, macro);
48 }
49 
50 /* Define the macros that we always expect to have on AArch64.  */
51 
52 static void
aarch64_define_unconditional_macros(cpp_reader * pfile)53 aarch64_define_unconditional_macros (cpp_reader *pfile)
54 {
55   builtin_define ("__aarch64__");
56   builtin_define ("__ARM_64BIT_STATE");
57 
58   builtin_define ("__ARM_ARCH_ISA_A64");
59   builtin_define_with_int_value ("__ARM_ALIGN_MAX_PWR", 28);
60   builtin_define_with_int_value ("__ARM_ALIGN_MAX_STACK_PWR", 16);
61 
62   /* __ARM_ARCH_8A is not mandated by ACLE but we define it unconditionally
63      as interoperability with the same arm macro.  */
64   builtin_define ("__ARM_ARCH_8A");
65 
66   builtin_define_with_int_value ("__ARM_ARCH_PROFILE",
67       AARCH64_ISA_V8_R ? 'R' : 'A');
68   builtin_define ("__ARM_FEATURE_CLZ");
69   builtin_define ("__ARM_FEATURE_IDIV");
70   builtin_define ("__ARM_FEATURE_UNALIGNED");
71   builtin_define ("__ARM_PCS_AAPCS64");
72   builtin_define_with_int_value ("__ARM_SIZEOF_WCHAR_T", WCHAR_TYPE_SIZE / 8);
73 
74   builtin_define ("__GCC_ASM_FLAG_OUTPUTS__");
75 }
76 
77 /* Undefine/redefine macros that depend on the current backend state and may
78    need to change when a target pragma modifies the backend state.  */
79 
80 static void
aarch64_update_cpp_builtins(cpp_reader * pfile)81 aarch64_update_cpp_builtins (cpp_reader *pfile)
82 {
83   aarch64_def_or_undef (flag_unsafe_math_optimizations, "__ARM_FP_FAST", pfile);
84 
85   builtin_define_with_int_value ("__ARM_ARCH", aarch64_architecture_version);
86 
87   builtin_define_with_int_value ("__ARM_SIZEOF_MINIMAL_ENUM",
88 				 flag_short_enums ? 1 : 4);
89   aarch64_def_or_undef (TARGET_BIG_END, "__AARCH64EB__", pfile);
90   aarch64_def_or_undef (TARGET_BIG_END, "__ARM_BIG_ENDIAN", pfile);
91   aarch64_def_or_undef (!TARGET_BIG_END, "__AARCH64EL__", pfile);
92 
93   aarch64_def_or_undef (TARGET_FLOAT, "__ARM_FEATURE_FMA", pfile);
94 
95   if (TARGET_FLOAT || TARGET_SIMD)
96     {
97       builtin_define_with_int_value ("__ARM_FP", 0x0E);
98       builtin_define ("__ARM_FP16_FORMAT_IEEE");
99       builtin_define ("__ARM_FP16_ARGS");
100     }
101   else
102     cpp_undef (pfile, "__ARM_FP");
103 
104   aarch64_def_or_undef (TARGET_FP_F16INST,
105 			"__ARM_FEATURE_FP16_SCALAR_ARITHMETIC", pfile);
106   aarch64_def_or_undef (TARGET_SIMD_F16INST,
107 			"__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", pfile);
108 
109   aarch64_def_or_undef (TARGET_SIMD, "__ARM_FEATURE_NUMERIC_MAXMIN", pfile);
110   aarch64_def_or_undef (TARGET_SIMD, "__ARM_NEON", pfile);
111 
112 
113   aarch64_def_or_undef (TARGET_CRC32, "__ARM_FEATURE_CRC32", pfile);
114   aarch64_def_or_undef (TARGET_DOTPROD, "__ARM_FEATURE_DOTPROD", pfile);
115   aarch64_def_or_undef (TARGET_COMPLEX, "__ARM_FEATURE_COMPLEX", pfile);
116   aarch64_def_or_undef (TARGET_JSCVT, "__ARM_FEATURE_JCVT", pfile);
117 
118   cpp_undef (pfile, "__AARCH64_CMODEL_TINY__");
119   cpp_undef (pfile, "__AARCH64_CMODEL_SMALL__");
120   cpp_undef (pfile, "__AARCH64_CMODEL_LARGE__");
121 
122   switch (aarch64_cmodel)
123     {
124       case AARCH64_CMODEL_TINY:
125       case AARCH64_CMODEL_TINY_PIC:
126 	builtin_define ("__AARCH64_CMODEL_TINY__");
127 	break;
128       case AARCH64_CMODEL_SMALL:
129       case AARCH64_CMODEL_SMALL_PIC:
130 	builtin_define ("__AARCH64_CMODEL_SMALL__");
131 	break;
132       case AARCH64_CMODEL_LARGE:
133 	builtin_define ("__AARCH64_CMODEL_LARGE__");
134 	break;
135       default:
136 	break;
137     }
138 
139   aarch64_def_or_undef (TARGET_ILP32, "_ILP32", pfile);
140   aarch64_def_or_undef (TARGET_ILP32, "__ILP32__", pfile);
141 
142   aarch64_def_or_undef (TARGET_CRYPTO, "__ARM_FEATURE_CRYPTO", pfile);
143   aarch64_def_or_undef (TARGET_SIMD_RDMA, "__ARM_FEATURE_QRDMX", pfile);
144   aarch64_def_or_undef (TARGET_SVE, "__ARM_FEATURE_SVE", pfile);
145   cpp_undef (pfile, "__ARM_FEATURE_SVE_BITS");
146   if (TARGET_SVE)
147     {
148       int bits;
149       if (!BITS_PER_SVE_VECTOR.is_constant (&bits))
150 	bits = 0;
151       builtin_define_with_int_value ("__ARM_FEATURE_SVE_BITS", bits);
152     }
153   aarch64_def_or_undef (TARGET_SVE, "__ARM_FEATURE_SVE_VECTOR_OPERATORS",
154 			pfile);
155   aarch64_def_or_undef (TARGET_SVE_I8MM,
156 			"__ARM_FEATURE_SVE_MATMUL_INT8", pfile);
157   aarch64_def_or_undef (TARGET_SVE_F32MM,
158 			"__ARM_FEATURE_SVE_MATMUL_FP32", pfile);
159   aarch64_def_or_undef (TARGET_SVE_F64MM,
160 			"__ARM_FEATURE_SVE_MATMUL_FP64", pfile);
161   aarch64_def_or_undef (TARGET_SVE2, "__ARM_FEATURE_SVE2", pfile);
162   aarch64_def_or_undef (TARGET_SVE2_AES, "__ARM_FEATURE_SVE2_AES", pfile);
163   aarch64_def_or_undef (TARGET_SVE2_BITPERM,
164 			"__ARM_FEATURE_SVE2_BITPERM", pfile);
165   aarch64_def_or_undef (TARGET_SVE2_SHA3, "__ARM_FEATURE_SVE2_SHA3", pfile);
166   aarch64_def_or_undef (TARGET_SVE2_SM4, "__ARM_FEATURE_SVE2_SM4", pfile);
167 
168   aarch64_def_or_undef (TARGET_LSE, "__ARM_FEATURE_ATOMICS", pfile);
169   aarch64_def_or_undef (TARGET_AES, "__ARM_FEATURE_AES", pfile);
170   aarch64_def_or_undef (TARGET_SHA2, "__ARM_FEATURE_SHA2", pfile);
171   aarch64_def_or_undef (TARGET_SHA3, "__ARM_FEATURE_SHA3", pfile);
172   aarch64_def_or_undef (TARGET_SHA3, "__ARM_FEATURE_SHA512", pfile);
173   aarch64_def_or_undef (TARGET_SM4, "__ARM_FEATURE_SM3", pfile);
174   aarch64_def_or_undef (TARGET_SM4, "__ARM_FEATURE_SM4", pfile);
175   aarch64_def_or_undef (TARGET_F16FML, "__ARM_FEATURE_FP16_FML", pfile);
176 
177   aarch64_def_or_undef (TARGET_FRINT, "__ARM_FEATURE_FRINT", pfile);
178   aarch64_def_or_undef (TARGET_TME, "__ARM_FEATURE_TME", pfile);
179   aarch64_def_or_undef (TARGET_RNG, "__ARM_FEATURE_RNG", pfile);
180   aarch64_def_or_undef (TARGET_MEMTAG, "__ARM_FEATURE_MEMORY_TAGGING", pfile);
181 
182   aarch64_def_or_undef (aarch64_bti_enabled (),
183 			"__ARM_FEATURE_BTI_DEFAULT", pfile);
184 
185   cpp_undef (pfile, "__ARM_FEATURE_PAC_DEFAULT");
186   if (aarch64_ra_sign_scope != AARCH64_FUNCTION_NONE)
187     {
188       int v = 0;
189       if (aarch64_ra_sign_key == AARCH64_KEY_A)
190 	v |= 1;
191       if (aarch64_ra_sign_key == AARCH64_KEY_B)
192 	v |= 2;
193       if (aarch64_ra_sign_scope == AARCH64_FUNCTION_ALL)
194 	v |= 4;
195       builtin_define_with_int_value ("__ARM_FEATURE_PAC_DEFAULT", v);
196     }
197 
198   aarch64_def_or_undef (TARGET_I8MM, "__ARM_FEATURE_MATMUL_INT8", pfile);
199   aarch64_def_or_undef (TARGET_BF16_SIMD,
200 			"__ARM_FEATURE_BF16_VECTOR_ARITHMETIC", pfile);
201   aarch64_def_or_undef (TARGET_BF16_FP,
202 			"__ARM_FEATURE_BF16_SCALAR_ARITHMETIC", pfile);
203   aarch64_def_or_undef (TARGET_LS64,
204 			"__ARM_FEATURE_LS64", pfile);
205   aarch64_def_or_undef (AARCH64_ISA_RCPC, "__ARM_FEATURE_RCPC", pfile);
206 
207   /* Not for ACLE, but required to keep "float.h" correct if we switch
208      target between implementations that do or do not support ARMv8.2-A
209      16-bit floating-point extensions.  */
210   cpp_undef (pfile, "__FLT_EVAL_METHOD__");
211   builtin_define_with_int_value ("__FLT_EVAL_METHOD__",
212 				 c_flt_eval_method (true));
213   cpp_undef (pfile, "__FLT_EVAL_METHOD_C99__");
214   builtin_define_with_int_value ("__FLT_EVAL_METHOD_C99__",
215 				 c_flt_eval_method (false));
216 }
217 
218 /* Implement TARGET_CPU_CPP_BUILTINS.  */
219 
220 void
aarch64_cpu_cpp_builtins(cpp_reader * pfile)221 aarch64_cpu_cpp_builtins (cpp_reader *pfile)
222 {
223   aarch64_define_unconditional_macros (pfile);
224   aarch64_update_cpp_builtins (pfile);
225 }
226 
227 /* Hook to validate the current #pragma GCC target and set the state, and
228    update the macros based on what was changed.  If ARGS is NULL, then
229    POP_TARGET is used to reset the options.  */
230 
231 static bool
aarch64_pragma_target_parse(tree args,tree pop_target)232 aarch64_pragma_target_parse (tree args, tree pop_target)
233 {
234   /* If args is not NULL then process it and setup the target-specific
235      information that it specifies.  */
236   if (args)
237     {
238       if (!aarch64_process_target_attr (args))
239 	return false;
240 
241       aarch64_override_options_internal (&global_options);
242     }
243 
244   /* args is NULL, restore to the state described in pop_target.  */
245   else
246     {
247       pop_target = pop_target ? pop_target : target_option_default_node;
248       cl_target_option_restore (&global_options, &global_options_set,
249 				TREE_TARGET_OPTION (pop_target));
250     }
251 
252   target_option_current_node
253     = build_target_option_node (&global_options, &global_options_set);
254 
255   aarch64_reset_previous_fndecl ();
256   /* For the definitions, ensure all newly defined macros are considered
257      as used for -Wunused-macros.  There is no point warning about the
258      compiler predefined macros.  */
259   cpp_options *cpp_opts = cpp_get_options (parse_in);
260   unsigned char saved_warn_unused_macros = cpp_opts->warn_unused_macros;
261   cpp_opts->warn_unused_macros = 0;
262 
263   cpp_force_token_locations (parse_in, BUILTINS_LOCATION);
264   aarch64_update_cpp_builtins (parse_in);
265   cpp_stop_forcing_token_locations (parse_in);
266 
267   cpp_opts->warn_unused_macros = saved_warn_unused_macros;
268 
269   /* If we're popping or reseting make sure to update the globals so that
270      the optab availability predicates get recomputed.  */
271   if (pop_target)
272     aarch64_save_restore_target_globals (pop_target);
273 
274   /* Initialize SIMD builtins if we haven't already.
275      Set current_target_pragma to NULL for the duration so that
276      the builtin initialization code doesn't try to tag the functions
277      being built with the attributes specified by any current pragma, thus
278      going into an infinite recursion.  */
279   if (TARGET_SIMD)
280     {
281       tree saved_current_target_pragma = current_target_pragma;
282       current_target_pragma = NULL;
283       aarch64_init_simd_builtins ();
284       current_target_pragma = saved_current_target_pragma;
285     }
286 
287   return true;
288 }
289 
290 /* Implement "#pragma GCC aarch64".  */
291 static void
aarch64_pragma_aarch64(cpp_reader *)292 aarch64_pragma_aarch64 (cpp_reader *)
293 {
294   tree x;
295   if (pragma_lex (&x) != CPP_STRING)
296     {
297       error ("%<#pragma GCC aarch64%> requires a string parameter");
298       return;
299     }
300 
301   const char *name = TREE_STRING_POINTER (x);
302   if (strcmp (name, "arm_sve.h") == 0)
303     aarch64_sve::handle_arm_sve_h ();
304   else if (strcmp (name, "arm_neon.h") == 0)
305     handle_arm_neon_h ();
306   else if (strcmp (name, "arm_acle.h") == 0)
307     handle_arm_acle_h ();
308   else
309     error ("unknown %<#pragma GCC aarch64%> option %qs", name);
310 }
311 
312 /* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN.  */
313 static tree
aarch64_resolve_overloaded_builtin(unsigned int uncast_location,tree fndecl,void * uncast_arglist)314 aarch64_resolve_overloaded_builtin (unsigned int uncast_location,
315 				    tree fndecl, void *uncast_arglist)
316 {
317   vec<tree, va_gc> empty = {};
318   location_t location = (location_t) uncast_location;
319   vec<tree, va_gc> *arglist = (uncast_arglist
320 			       ? (vec<tree, va_gc> *) uncast_arglist
321 			       : &empty);
322   unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
323   unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT;
324   tree new_fndecl;
325   switch (code & AARCH64_BUILTIN_CLASS)
326     {
327     case AARCH64_BUILTIN_GENERAL:
328       return aarch64_resolve_overloaded_builtin_general (location, fndecl,
329 							 uncast_arglist);
330     case AARCH64_BUILTIN_SVE:
331       new_fndecl = aarch64_sve::resolve_overloaded_builtin (location, subcode,
332 							    arglist);
333       break;
334     }
335   if (new_fndecl == NULL_TREE || new_fndecl == error_mark_node)
336     return new_fndecl;
337   return build_function_call_vec (location, vNULL, new_fndecl, arglist,
338 				  NULL, fndecl);
339 }
340 
341 /* Implement TARGET_CHECK_BUILTIN_CALL.  */
342 static bool
aarch64_check_builtin_call(location_t loc,vec<location_t> arg_loc,tree fndecl,tree orig_fndecl,unsigned int nargs,tree * args)343 aarch64_check_builtin_call (location_t loc, vec<location_t> arg_loc,
344 			    tree fndecl, tree orig_fndecl,
345 			    unsigned int nargs, tree *args)
346 {
347   unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
348   unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT;
349   switch (code & AARCH64_BUILTIN_CLASS)
350     {
351     case AARCH64_BUILTIN_GENERAL:
352       return true;
353 
354     case AARCH64_BUILTIN_SVE:
355       return aarch64_sve::check_builtin_call (loc, arg_loc, subcode,
356 					      orig_fndecl, nargs, args);
357     }
358   gcc_unreachable ();
359 }
360 
361 /* Implement REGISTER_TARGET_PRAGMAS.  */
362 
363 void
aarch64_register_pragmas(void)364 aarch64_register_pragmas (void)
365 {
366   /* Update pragma hook to allow parsing #pragma GCC target.  */
367   targetm.target_option.pragma_parse = aarch64_pragma_target_parse;
368 
369   targetm.resolve_overloaded_builtin = aarch64_resolve_overloaded_builtin;
370   targetm.check_builtin_call = aarch64_check_builtin_call;
371 
372   c_register_pragma ("GCC", "aarch64", aarch64_pragma_aarch64);
373 }
374