1 /* Common hooks for AArch64.
2    Copyright (C) 2012-2018 Free Software Foundation, Inc.
3    Contributed by ARM Ltd.
4 
5    This file is part of GCC.
6 
7    GCC is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published
9    by the Free Software Foundation; either version 3, or (at your
10    option) any later version.
11 
12    GCC is distributed in the hope that it will be useful, but WITHOUT
13    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15    License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with GCC; see the file COPYING3.  If not see
19    <http://www.gnu.org/licenses/>.  */
20 
21 #include "config.h"
22 #define INCLUDE_STRING
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "memmodel.h"
27 #include "tm_p.h"
28 #include "common/common-target.h"
29 #include "common/common-target-def.h"
30 #include "opts.h"
31 #include "flags.h"
32 #include "diagnostic.h"
33 
34 #ifdef  TARGET_BIG_ENDIAN_DEFAULT
35 #undef  TARGET_DEFAULT_TARGET_FLAGS
36 #define TARGET_DEFAULT_TARGET_FLAGS (MASK_BIG_END)
37 #endif
38 
39 #undef  TARGET_HANDLE_OPTION
40 #define TARGET_HANDLE_OPTION aarch64_handle_option
41 
42 #undef	TARGET_OPTION_OPTIMIZATION_TABLE
43 #define TARGET_OPTION_OPTIMIZATION_TABLE aarch_option_optimization_table
44 
45 /* Set default optimization options.  */
46 static const struct default_options aarch_option_optimization_table[] =
47   {
48     /* Enable section anchors by default at -O1 or higher.  */
49     { OPT_LEVELS_1_PLUS, OPT_fsection_anchors, NULL, 1 },
50     /* Disable fomit-frame-pointer by default.  */
51     { OPT_LEVELS_ALL, OPT_fomit_frame_pointer, NULL, 0 },
52     /* Enable -fsched-pressure by default when optimizing.  */
53     { OPT_LEVELS_1_PLUS, OPT_fsched_pressure, NULL, 1 },
54     /* Enable redundant extension instructions removal at -O2 and higher.  */
55     { OPT_LEVELS_2_PLUS, OPT_free, NULL, 1 },
56 #if (TARGET_DEFAULT_ASYNC_UNWIND_TABLES == 1)
57     { OPT_LEVELS_ALL, OPT_fasynchronous_unwind_tables, NULL, 1 },
58     { OPT_LEVELS_ALL, OPT_funwind_tables, NULL, 1},
59 #endif
60     { OPT_LEVELS_NONE, 0, NULL, 0 }
61   };
62 
63 /* Implement TARGET_HANDLE_OPTION.
64    This function handles the target specific options for CPU/target selection.
65 
66    -mcpu=CPU is shorthand for -march=ARCH_FOR_CPU, -mtune=CPU.
67    If either of -march or -mtune is given, they override their
68    respective component of -mcpu.  This logic is implemented
69    in config/aarch64/aarch64.c:aarch64_override_options.  */
70 
71 bool
aarch64_handle_option(struct gcc_options * opts,struct gcc_options * opts_set ATTRIBUTE_UNUSED,const struct cl_decoded_option * decoded,location_t loc ATTRIBUTE_UNUSED)72 aarch64_handle_option (struct gcc_options *opts,
73 		       struct gcc_options *opts_set ATTRIBUTE_UNUSED,
74 		       const struct cl_decoded_option *decoded,
75 		       location_t loc ATTRIBUTE_UNUSED)
76 {
77   size_t code = decoded->opt_index;
78   const char *arg = decoded->arg;
79   int val = decoded->value;
80 
81   switch (code)
82     {
83     case OPT_march_:
84       opts->x_aarch64_arch_string = arg;
85       return true;
86 
87     case OPT_mcpu_:
88       opts->x_aarch64_cpu_string = arg;
89       return true;
90 
91     case OPT_mtune_:
92       opts->x_aarch64_tune_string = arg;
93       return true;
94 
95     case OPT_mgeneral_regs_only:
96       opts->x_target_flags |= MASK_GENERAL_REGS_ONLY;
97       return true;
98 
99     case OPT_mfix_cortex_a53_835769:
100       opts->x_aarch64_fix_a53_err835769 = val;
101       return true;
102 
103     case OPT_mstrict_align:
104       opts->x_target_flags |= MASK_STRICT_ALIGN;
105       return true;
106 
107     case OPT_momit_leaf_frame_pointer:
108       opts->x_flag_omit_leaf_frame_pointer = val;
109       return true;
110 
111     default:
112       return true;
113     }
114 }
115 
116 struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;
117 
118 /* An ISA extension in the co-processor and main instruction set space.  */
119 struct aarch64_option_extension
120 {
121   const char *const name;
122   const unsigned long flag_canonical;
123   const unsigned long flags_on;
124   const unsigned long flags_off;
125 };
126 
127 /* ISA extensions in AArch64.  */
128 static const struct aarch64_option_extension all_extensions[] =
129 {
130 #define AARCH64_OPT_EXTENSION(NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, Z) \
131   {NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF},
132 #include "config/aarch64/aarch64-option-extensions.def"
133   {NULL, 0, 0, 0}
134 };
135 
136 struct processor_name_to_arch
137 {
138   const std::string processor_name;
139   const enum aarch64_arch arch;
140   const unsigned long flags;
141 };
142 
143 struct arch_to_arch_name
144 {
145   const enum aarch64_arch arch;
146   const std::string arch_name;
147   const unsigned long flags;
148 };
149 
150 /* Map processor names to the architecture revision they implement and
151    the default set of architectural feature flags they support.  */
152 static const struct processor_name_to_arch all_cores[] =
153 {
154 #define AARCH64_CORE(NAME, X, IDENT, ARCH_IDENT, FLAGS, COSTS, IMP, PART, VARIANT) \
155   {NAME, AARCH64_ARCH_##ARCH_IDENT, FLAGS},
156 #include "config/aarch64/aarch64-cores.def"
157   {"generic", AARCH64_ARCH_8A, AARCH64_FL_FOR_ARCH8},
158   {"", aarch64_no_arch, 0}
159 };
160 
161 /* Map architecture revisions to their string representation.  */
162 static const struct arch_to_arch_name all_architectures[] =
163 {
164 #define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH, FLAGS) \
165   {AARCH64_ARCH_##ARCH_IDENT, NAME, FLAGS},
166 #include "config/aarch64/aarch64-arches.def"
167   {aarch64_no_arch, "", 0}
168 };
169 
170 /* Parse the architecture extension string STR and update ISA_FLAGS
171    with the architecture features turned on or off.  Return a
172    aarch64_parse_opt_result describing the result.  */
173 
174 enum aarch64_parse_opt_result
aarch64_parse_extension(const char * str,unsigned long * isa_flags)175 aarch64_parse_extension (const char *str, unsigned long *isa_flags)
176 {
177   /* The extension string is parsed left to right.  */
178   const struct aarch64_option_extension *opt = NULL;
179 
180   /* Flag to say whether we are adding or removing an extension.  */
181   int adding_ext = -1;
182 
183   while (str != NULL && *str != 0)
184     {
185       const char *ext;
186       size_t len;
187 
188       str++;
189       ext = strchr (str, '+');
190 
191       if (ext != NULL)
192 	len = ext - str;
193       else
194 	len = strlen (str);
195 
196       if (len >= 2 && strncmp (str, "no", 2) == 0)
197 	{
198 	  adding_ext = 0;
199 	  len -= 2;
200 	  str += 2;
201 	}
202       else if (len > 0)
203 	adding_ext = 1;
204 
205       if (len == 0)
206 	return AARCH64_PARSE_MISSING_ARG;
207 
208 
209       /* Scan over the extensions table trying to find an exact match.  */
210       for (opt = all_extensions; opt->name != NULL; opt++)
211 	{
212 	  if (strlen (opt->name) == len && strncmp (opt->name, str, len) == 0)
213 	    {
214 	      /* Add or remove the extension.  */
215 	      if (adding_ext)
216 		*isa_flags |= (opt->flags_on | opt->flag_canonical);
217 	      else
218 		*isa_flags &= ~(opt->flags_off | opt->flag_canonical);
219 	      break;
220 	    }
221 	}
222 
223       if (opt->name == NULL)
224 	{
225 	  /* Extension not found in list.  */
226 	  return AARCH64_PARSE_INVALID_FEATURE;
227 	}
228 
229       str = ext;
230     };
231 
232   return AARCH64_PARSE_OK;
233 }
234 
235 /* Return a string representation of ISA_FLAGS.  DEFAULT_ARCH_FLAGS
236    gives the default set of flags which are implied by whatever -march
237    we'd put out.  Our job is to figure out the minimal set of "+" and
238    "+no" feature flags to put out, and to put them out grouped such
239    that all the "+" flags come before the "+no" flags.  */
240 
241 std::string
aarch64_get_extension_string_for_isa_flags(unsigned long isa_flags,unsigned long default_arch_flags)242 aarch64_get_extension_string_for_isa_flags (unsigned long isa_flags,
243 					    unsigned long default_arch_flags)
244 {
245   const struct aarch64_option_extension *opt = NULL;
246   std::string outstr = "";
247 
248   /* Pass one: Find all the things we need to turn on.  As a special case,
249      we always want to put out +crc if it is enabled.  */
250   for (opt = all_extensions; opt->name != NULL; opt++)
251     if ((isa_flags & opt->flag_canonical
252 	 && !(default_arch_flags & opt->flag_canonical))
253 	|| (default_arch_flags & opt->flag_canonical
254             && opt->flag_canonical == AARCH64_ISA_CRC))
255       {
256 	outstr += "+";
257 	outstr += opt->name;
258       }
259 
260   /* Pass two: Find all the things we need to turn off.  */
261   for (opt = all_extensions; opt->name != NULL; opt++)
262     if ((~isa_flags) & opt->flag_canonical
263 	&& !((~default_arch_flags) & opt->flag_canonical))
264       {
265 	outstr += "+no";
266 	outstr += opt->name;
267       }
268 
269   return outstr;
270 }
271 
272 /* Attempt to rewrite NAME, which has been passed on the command line
273    as a -mcpu option to an equivalent -march value.  If we can do so,
274    return the new string, otherwise return an error.  */
275 
276 const char *
aarch64_rewrite_selected_cpu(const char * name)277 aarch64_rewrite_selected_cpu (const char *name)
278 {
279   std::string original_string (name);
280   std::string extension_str;
281   std::string processor;
282   size_t extension_pos = original_string.find_first_of ('+');
283 
284   /* Strip and save the extension string.  */
285   if (extension_pos != std::string::npos)
286     {
287       processor = original_string.substr (0, extension_pos);
288       extension_str = original_string.substr (extension_pos,
289 					      std::string::npos);
290     }
291   else
292     {
293       /* No extensions.  */
294       processor = original_string;
295     }
296 
297   const struct processor_name_to_arch* p_to_a;
298   for (p_to_a = all_cores;
299        p_to_a->arch != aarch64_no_arch;
300        p_to_a++)
301     {
302       if (p_to_a->processor_name == processor)
303 	break;
304     }
305 
306   const struct arch_to_arch_name* a_to_an;
307   for (a_to_an = all_architectures;
308        a_to_an->arch != aarch64_no_arch;
309        a_to_an++)
310     {
311       if (a_to_an->arch == p_to_a->arch)
312 	break;
313     }
314 
315   /* We couldn't find that proceesor name, or the processor name we
316      found does not map to an architecture we understand.  */
317   if (p_to_a->arch == aarch64_no_arch
318       || a_to_an->arch == aarch64_no_arch)
319     fatal_error (input_location, "unknown value %qs for -mcpu", name);
320 
321   unsigned long extensions = p_to_a->flags;
322   aarch64_parse_extension (extension_str.c_str (), &extensions);
323 
324   std::string outstr = a_to_an->arch_name
325 	+ aarch64_get_extension_string_for_isa_flags (extensions,
326 						      a_to_an->flags);
327 
328   /* We are going to memory leak here, nobody elsewhere
329      in the callchain is going to clean up after us.  The alternative is
330      to allocate a static buffer, and assert that it is big enough for our
331      modified string, which seems much worse!  */
332   return xstrdup (outstr.c_str ());
333 }
334 
335 /* Called by the driver to rewrite a name passed to the -mcpu
336    argument in preparation to be passed to the assembler.  The
337    names passed from the commend line will be in ARGV, we want
338    to use the right-most argument, which should be in
339    ARGV[ARGC - 1].  ARGC should always be greater than 0.  */
340 
341 const char *
aarch64_rewrite_mcpu(int argc,const char ** argv)342 aarch64_rewrite_mcpu (int argc, const char **argv)
343 {
344   gcc_assert (argc);
345   return aarch64_rewrite_selected_cpu (argv[argc - 1]);
346 }
347 
348 #undef AARCH64_CPU_NAME_LENGTH
349 
350