summaryrefslogtreecommitdiff
path: root/gcc/common/config/powerpcspe/powerpcspe-common.c
blob: 5f70666416e6d3cdb30a2973c54b297b70320055 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
/* Common hooks for IBM RS/6000.
   Copyright (C) 1991-2019 Free Software Foundation, Inc.

   This file is part of GCC.

   GCC is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published
   by the Free Software Foundation; either version 3, or (at your
   option) any later version.

   GCC is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
   License for more details.

   You should have received a copy of the GNU General Public License
   along with GCC; see the file COPYING3.  If not see
   <http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "diagnostic-core.h"
#include "tm.h"
#include "common/common-target.h"
#include "common/common-target-def.h"
#include "opts.h"
#include "flags.h"
#include "params.h"

/* Implement TARGET_OPTION_OPTIMIZATION_TABLE.  */
static const struct default_options rs6000_option_optimization_table[] =
  {
    /* Enable -fsched-pressure for first pass instruction scheduling.  */
    { OPT_LEVELS_1_PLUS, OPT_fsched_pressure, NULL, 1 },
    { OPT_LEVELS_NONE, 0, NULL, 0 }
  };

/* Implement TARGET_OPTION_INIT_STRUCT.  */

static void
rs6000_option_init_struct (struct gcc_options *opts)
{
  if (DEFAULT_ABI == ABI_DARWIN)
    /* The Darwin libraries never set errno, so we might as well
       avoid calling them when that's the only reason we would.  */
    opts->x_flag_errno_math = 0;

  /* Enable section anchors by default.  */
  if (!TARGET_MACHO)
    opts->x_flag_section_anchors = 1;
}

/* Implement TARGET_OPTION_DEFAULT_PARAMS.  */

static void
rs6000_option_default_params (void)
{
  /* Double growth factor to counter reduced min jump length.  */
  set_default_param_value (PARAM_MAX_GROW_COPY_BB_INSNS, 16);
}

/* If not otherwise specified by a target, make 'long double' equivalent to
   'double'.  */

#ifndef RS6000_DEFAULT_LONG_DOUBLE_SIZE
#define RS6000_DEFAULT_LONG_DOUBLE_SIZE 64
#endif

/* Implement TARGET_HANDLE_OPTION.  */

static bool
rs6000_handle_option (struct gcc_options *opts, struct gcc_options *opts_set,
		      const struct cl_decoded_option *decoded,
		      location_t loc)
{
  enum fpu_type_t fpu_type = FPU_NONE;
  char *p, *q;
  size_t code = decoded->opt_index;
  const char *arg = decoded->arg;
  int value = decoded->value;

  switch (code)
    {
    case OPT_mfull_toc:
      opts->x_rs6000_isa_flags &= ~OPTION_MASK_MINIMAL_TOC;
      opts->x_TARGET_NO_FP_IN_TOC = 0;
      opts->x_TARGET_NO_SUM_IN_TOC = 0;
      opts_set->x_rs6000_isa_flags |= OPTION_MASK_MINIMAL_TOC;
#ifdef TARGET_USES_SYSV4_OPT
      /* Note, V.4 no longer uses a normal TOC, so make -mfull-toc, be
	 just the same as -mminimal-toc.  */
      opts->x_rs6000_isa_flags |= OPTION_MASK_MINIMAL_TOC;
      opts_set->x_rs6000_isa_flags |= OPTION_MASK_MINIMAL_TOC;
#endif
      break;

#ifdef TARGET_USES_SYSV4_OPT
    case OPT_mtoc:
      /* Make -mtoc behave like -mminimal-toc.  */
      opts->x_rs6000_isa_flags |= OPTION_MASK_MINIMAL_TOC;
      opts_set->x_rs6000_isa_flags |= OPTION_MASK_MINIMAL_TOC;
      break;
#endif

#ifdef TARGET_USES_AIX64_OPT
    case OPT_maix64:
#else
    case OPT_m64:
#endif
      opts->x_rs6000_isa_flags |= OPTION_MASK_POWERPC64;
      opts->x_rs6000_isa_flags |= (~opts_set->x_rs6000_isa_flags
				   & OPTION_MASK_PPC_GFXOPT);
      opts_set->x_rs6000_isa_flags |= OPTION_MASK_POWERPC64;
      break;

#ifdef TARGET_USES_AIX64_OPT
    case OPT_maix32:
#else
    case OPT_m32:
#endif
      opts->x_rs6000_isa_flags &= ~OPTION_MASK_POWERPC64;
      opts_set->x_rs6000_isa_flags |= OPTION_MASK_POWERPC64;
      break;

    case OPT_mminimal_toc:
      if (value == 1)
	{
	  opts->x_TARGET_NO_FP_IN_TOC = 0;
	  opts->x_TARGET_NO_SUM_IN_TOC = 0;
	}
      break;

    case OPT_mpowerpc_gpopt:
    case OPT_mpowerpc_gfxopt:
      break;

    case OPT_mdebug_:
      p = ASTRDUP (arg);
      opts->x_rs6000_debug = 0;

      while ((q = strtok (p, ",")) != NULL)
	{
	  unsigned mask = 0;
	  bool invert;

	  p = NULL;
	  if (*q == '!')
	    {
	      invert = true;
	      q++;
	    }
	  else
	    invert = false;

	  if (! strcmp (q, "all"))
	    mask = MASK_DEBUG_ALL;
	  else if (! strcmp (q, "stack"))
	    mask = MASK_DEBUG_STACK;
	  else if (! strcmp (q, "arg"))
	    mask = MASK_DEBUG_ARG;
	  else if (! strcmp (q, "reg"))
	    mask = MASK_DEBUG_REG;
	  else if (! strcmp (q, "addr"))
	    mask = MASK_DEBUG_ADDR;
	  else if (! strcmp (q, "cost"))
	    mask = MASK_DEBUG_COST;
	  else if (! strcmp (q, "target"))
	    mask = MASK_DEBUG_TARGET;
	  else if (! strcmp (q, "builtin"))
	    mask = MASK_DEBUG_BUILTIN;
	  else
	    error_at (loc, "unknown -mdebug-%s switch", q);

	  if (invert)
	    opts->x_rs6000_debug &= ~mask;
	  else	
	    opts->x_rs6000_debug |= mask;
	}
      break;

#ifdef TARGET_USES_SYSV4_OPT
    case OPT_mrelocatable:
      if (value == 1)
	{
	  opts->x_rs6000_isa_flags |= OPTION_MASK_MINIMAL_TOC;
	  opts_set->x_rs6000_isa_flags |= OPTION_MASK_MINIMAL_TOC;
	  opts->x_TARGET_NO_FP_IN_TOC = 1;
	}
      break;

    case OPT_mrelocatable_lib:
      if (value == 1)
	{
	  opts->x_rs6000_isa_flags |= (OPTION_MASK_RELOCATABLE
				       | OPTION_MASK_MINIMAL_TOC);
	  opts_set->x_rs6000_isa_flags |= (OPTION_MASK_RELOCATABLE
					   | OPTION_MASK_MINIMAL_TOC);
	  opts->x_TARGET_NO_FP_IN_TOC = 1;
	}
      else
	{
	  opts->x_rs6000_isa_flags &= ~OPTION_MASK_RELOCATABLE;
	  opts_set->x_rs6000_isa_flags |= OPTION_MASK_RELOCATABLE;
	}
      break;
#endif

    case OPT_mabi_altivec:
      /* Enabling the AltiVec ABI turns off the SPE ABI.  */
      opts->x_rs6000_spe_abi = 0;
      break;

    case OPT_mabi_spe:
      opts->x_rs6000_altivec_abi = 0;
      break;

    case OPT_mlong_double_:
      if (value != 64 && value != 128)
	{
	  error_at (loc, "unknown switch -mlong-double-%s", arg);
	  opts->x_rs6000_long_double_type_size
	    = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
	  return false;
	}
      break;

    case OPT_msingle_float:
      if (!TARGET_SINGLE_FPU) 
	warning_at (loc, 0,
		    "-msingle-float option equivalent to -mhard-float");
      /* -msingle-float implies -mno-double-float and TARGET_HARD_FLOAT. */
      opts->x_rs6000_double_float = 0;
      opts->x_rs6000_isa_flags &= ~OPTION_MASK_SOFT_FLOAT;
      opts_set->x_rs6000_isa_flags |= OPTION_MASK_SOFT_FLOAT;
      break;

    case OPT_mdouble_float:
      /* -mdouble-float implies -msingle-float and TARGET_HARD_FLOAT. */
      opts->x_rs6000_single_float = 1;
      opts->x_rs6000_isa_flags &= ~OPTION_MASK_SOFT_FLOAT;
      opts_set->x_rs6000_isa_flags |= OPTION_MASK_SOFT_FLOAT;
      break;

    case OPT_msimple_fpu:
      if (!TARGET_SINGLE_FPU) 
	warning_at (loc, 0, "-msimple-fpu option ignored");
      break;

    case OPT_mhard_float:
      /* -mhard_float implies -msingle-float and -mdouble-float. */
      opts->x_rs6000_single_float = opts->x_rs6000_double_float = 1;
      break;

    case OPT_msoft_float:
      /* -msoft_float implies -mnosingle-float and -mnodouble-float. */
      opts->x_rs6000_single_float = opts->x_rs6000_double_float = 0;
      break;

    case OPT_mfpu_:
      fpu_type = (enum fpu_type_t) value;
      if (fpu_type != FPU_NONE)
	{
	  /* If -mfpu is not none, then turn off SOFT_FLOAT, turn on
	     HARD_FLOAT. */
	  opts->x_rs6000_isa_flags &= ~OPTION_MASK_SOFT_FLOAT;
	  opts_set->x_rs6000_isa_flags |= OPTION_MASK_SOFT_FLOAT;
	  opts->x_rs6000_xilinx_fpu = 1;
	  if (fpu_type == FPU_SF_LITE || fpu_type == FPU_SF_FULL) 
	    opts->x_rs6000_single_float = 1;
	  if (fpu_type == FPU_DF_LITE || fpu_type == FPU_DF_FULL) 
	    opts->x_rs6000_single_float = opts->x_rs6000_double_float = 1;
	  if (fpu_type == FPU_SF_LITE || fpu_type == FPU_DF_LITE) 
	    opts->x_rs6000_simple_fpu = 1;
	}
      else
	{
	  /* -mfpu=none is equivalent to -msoft-float.  */
	  opts->x_rs6000_isa_flags |= OPTION_MASK_SOFT_FLOAT;
	  opts_set->x_rs6000_isa_flags |= OPTION_MASK_SOFT_FLOAT;
	  opts->x_rs6000_single_float = opts->x_rs6000_double_float = 0;
	}
      break;

    case OPT_mrecip:
      opts->x_rs6000_recip_name = (value) ? "default" : "none";
      break;
    }
  return true;
}

/* -fsplit-stack uses a field in the TCB, available with glibc-2.19.
   We also allow 2.18 because alignment padding guarantees that the
   space is available there too.  */

static bool
rs6000_supports_split_stack (bool report,
			     struct gcc_options *opts ATTRIBUTE_UNUSED)
{
#ifndef TARGET_GLIBC_MAJOR
#define TARGET_GLIBC_MAJOR 0
#endif
#ifndef TARGET_GLIBC_MINOR
#define TARGET_GLIBC_MINOR 0
#endif
  /* Note: Can't test DEFAULT_ABI here, it isn't set until later.  */
  if (TARGET_GLIBC_MAJOR * 1000 + TARGET_GLIBC_MINOR >= 2018
      && TARGET_64BIT
      && TARGET_ELF)
    return true;

  if (report)
    error ("%<-fsplit-stack%> currently only supported on PowerPC64 GNU/Linux with glibc-2.18 or later");
  return false;
}

#undef TARGET_HANDLE_OPTION
#define TARGET_HANDLE_OPTION rs6000_handle_option

#undef TARGET_OPTION_INIT_STRUCT
#define TARGET_OPTION_INIT_STRUCT rs6000_option_init_struct

#undef TARGET_OPTION_DEFAULT_PARAMS
#define TARGET_OPTION_DEFAULT_PARAMS rs6000_option_default_params

#undef TARGET_OPTION_OPTIMIZATION_TABLE
#define TARGET_OPTION_OPTIMIZATION_TABLE rs6000_option_optimization_table

#undef TARGET_SUPPORTS_SPLIT_STACK
#define TARGET_SUPPORTS_SPLIT_STACK rs6000_supports_split_stack

struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;