]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/bfin/bfin.c
target.def (handle_option): Take gcc_options and cl_decoded_option pointers and locat...
[thirdparty/gcc.git] / gcc / config / bfin / bfin.c
CommitLineData
f652d14b 1/* The Blackfin code generation auxiliary output file.
96e45421 2 Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
c75c517d 3 Free Software Foundation, Inc.
0d4a78eb
BS
4 Contributed by Analog Devices.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
2f83c7d6 10 by the Free Software Foundation; either version 3, or (at your
0d4a78eb
BS
11 option) any later version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
17
18 You should have received a copy of the GNU General Public License
2f83c7d6
NC
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
0d4a78eb
BS
21
22#include "config.h"
23#include "system.h"
24#include "coretypes.h"
25#include "tm.h"
26#include "rtl.h"
27#include "regs.h"
28#include "hard-reg-set.h"
0d4a78eb 29#include "insn-config.h"
3fb192d2 30#include "insn-codes.h"
0d4a78eb
BS
31#include "conditions.h"
32#include "insn-flags.h"
33#include "output.h"
34#include "insn-attr.h"
35#include "tree.h"
36#include "flags.h"
37#include "except.h"
38#include "function.h"
39#include "input.h"
40#include "target.h"
41#include "target-def.h"
42#include "expr.h"
718f9c0f 43#include "diagnostic-core.h"
0d4a78eb 44#include "recog.h"
42da70b7 45#include "optabs.h"
0d4a78eb
BS
46#include "ggc.h"
47#include "integrate.h"
9fc023cc 48#include "cgraph.h"
05905337 49#include "langhooks.h"
0d4a78eb
BS
50#include "bfin-protos.h"
51#include "tm-preds.h"
9fdd7520 52#include "tm-constrs.h"
0d4a78eb 53#include "gt-bfin.h"
b03149e1 54#include "basic-block.h"
ce27ef3d 55#include "cfglayout.h"
bbbc206e 56#include "timevar.h"
b18e284e 57#include "df.h"
d3c176fc 58#include "sel-sched.h"
96e45421 59#include "opts.h"
b03149e1
JZ
60
61/* A C structure for machine-specific, per-function data.
62 This is added to the cfun structure. */
d1b38208 63struct GTY(()) machine_function
b03149e1 64{
a848cf52
BS
65 /* Set if we are notified by the doloop pass that a hardware loop
66 was created. */
b03149e1 67 int has_hardware_loops;
9840d30a 68
a848cf52
BS
69 /* Set if we create a memcpy pattern that uses loop registers. */
70 int has_loopreg_clobber;
b03149e1 71};
0d4a78eb 72
0d4a78eb
BS
73/* RTX for condition code flag register and RETS register */
74extern GTY(()) rtx bfin_cc_rtx;
75extern GTY(()) rtx bfin_rets_rtx;
76rtx bfin_cc_rtx, bfin_rets_rtx;
77
78int max_arg_registers = 0;
79
80/* Arrays used when emitting register names. */
81const char *short_reg_names[] = SHORT_REGISTER_NAMES;
82const char *high_reg_names[] = HIGH_REGISTER_NAMES;
83const char *dregs_pair_names[] = DREGS_PAIR_NAMES;
84const char *byte_reg_names[] = BYTE_REGISTER_NAMES;
85
86static int arg_regs[] = FUNCTION_ARG_REGISTERS;
9840d30a 87static int ret_regs[] = FUNCTION_RETURN_REGISTERS;
0d4a78eb 88
c8de0f3b
BS
89/* Nonzero if -mshared-library-id was given. */
90static int bfin_lib_id_given;
0d4a78eb 91
bbbc206e
BS
92/* Nonzero if -fschedule-insns2 was given. We override it and
93 call the scheduler ourselves during reorg. */
94static int bfin_flag_schedule_insns2;
95
96/* Determines whether we run variable tracking in machine dependent
97 reorganization. */
98static int bfin_flag_var_tracking;
99
9d3f9aa3 100/* -mcpu support */
16869606 101bfin_cpu_t bfin_cpu_type = BFIN_CPU_UNKNOWN;
9d3f9aa3 102
ea2382be
JZ
103/* -msi-revision support. There are three special values:
104 -1 -msi-revision=none.
105 0xffff -msi-revision=any. */
106int bfin_si_revision;
107
108/* The workarounds enabled */
109unsigned int bfin_workarounds = 0;
110
111struct bfin_cpu
112{
113 const char *name;
114 bfin_cpu_t type;
115 int si_revision;
116 unsigned int workarounds;
117};
118
119struct bfin_cpu bfin_cpus[] =
120{
318b3009 121 {"bf512", BFIN_CPU_BF512, 0x0000,
b3187e24 122 WA_SPECULATIVE_LOADS | WA_05000074},
318b3009
BS
123
124 {"bf514", BFIN_CPU_BF514, 0x0000,
b3187e24 125 WA_SPECULATIVE_LOADS | WA_05000074},
318b3009
BS
126
127 {"bf516", BFIN_CPU_BF516, 0x0000,
b3187e24 128 WA_SPECULATIVE_LOADS | WA_05000074},
318b3009
BS
129
130 {"bf518", BFIN_CPU_BF518, 0x0000,
b3187e24 131 WA_SPECULATIVE_LOADS | WA_05000074},
318b3009
BS
132
133 {"bf522", BFIN_CPU_BF522, 0x0002,
b3187e24 134 WA_SPECULATIVE_LOADS | WA_05000074},
a6340be1 135 {"bf522", BFIN_CPU_BF522, 0x0001,
b3187e24 136 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
ea2382be 137 {"bf522", BFIN_CPU_BF522, 0x0000,
b3187e24 138 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
ea2382be 139
318b3009 140 {"bf523", BFIN_CPU_BF523, 0x0002,
b3187e24 141 WA_SPECULATIVE_LOADS | WA_05000074},
a6340be1 142 {"bf523", BFIN_CPU_BF523, 0x0001,
b3187e24 143 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
64882649 144 {"bf523", BFIN_CPU_BF523, 0x0000,
b3187e24 145 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
64882649 146
318b3009 147 {"bf524", BFIN_CPU_BF524, 0x0002,
b3187e24 148 WA_SPECULATIVE_LOADS | WA_05000074},
a6340be1 149 {"bf524", BFIN_CPU_BF524, 0x0001,
b3187e24 150 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
64882649 151 {"bf524", BFIN_CPU_BF524, 0x0000,
b3187e24 152 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
64882649 153
318b3009 154 {"bf525", BFIN_CPU_BF525, 0x0002,
b3187e24 155 WA_SPECULATIVE_LOADS | WA_05000074},
a6340be1 156 {"bf525", BFIN_CPU_BF525, 0x0001,
b3187e24 157 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
ea2382be 158 {"bf525", BFIN_CPU_BF525, 0x0000,
b3187e24 159 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
ea2382be 160
318b3009 161 {"bf526", BFIN_CPU_BF526, 0x0002,
b3187e24 162 WA_SPECULATIVE_LOADS | WA_05000074},
a6340be1 163 {"bf526", BFIN_CPU_BF526, 0x0001,
b3187e24 164 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
64882649 165 {"bf526", BFIN_CPU_BF526, 0x0000,
b3187e24 166 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
64882649 167
318b3009 168 {"bf527", BFIN_CPU_BF527, 0x0002,
b3187e24 169 WA_SPECULATIVE_LOADS | WA_05000074},
a6340be1 170 {"bf527", BFIN_CPU_BF527, 0x0001,
b3187e24 171 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
ea2382be 172 {"bf527", BFIN_CPU_BF527, 0x0000,
b3187e24 173 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
ea2382be 174
318b3009 175 {"bf531", BFIN_CPU_BF531, 0x0006,
b3187e24 176 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074},
ea2382be 177 {"bf531", BFIN_CPU_BF531, 0x0005,
b3187e24
BS
178 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315
179 | WA_LOAD_LCREGS | WA_05000074},
ea2382be 180 {"bf531", BFIN_CPU_BF531, 0x0004,
669eeb28 181 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
b3187e24
BS
182 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
183 | WA_05000074},
ea2382be 184 {"bf531", BFIN_CPU_BF531, 0x0003,
669eeb28 185 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
b3187e24
BS
186 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
187 | WA_05000074},
ea2382be 188
318b3009 189 {"bf532", BFIN_CPU_BF532, 0x0006,
b3187e24 190 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074},
ea2382be 191 {"bf532", BFIN_CPU_BF532, 0x0005,
b3187e24
BS
192 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315
193 | WA_LOAD_LCREGS | WA_05000074},
ea2382be 194 {"bf532", BFIN_CPU_BF532, 0x0004,
669eeb28 195 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
b3187e24
BS
196 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
197 | WA_05000074},
ea2382be 198 {"bf532", BFIN_CPU_BF532, 0x0003,
669eeb28 199 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
b3187e24
BS
200 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
201 | WA_05000074},
ea2382be 202
318b3009 203 {"bf533", BFIN_CPU_BF533, 0x0006,
b3187e24 204 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074},
ea2382be 205 {"bf533", BFIN_CPU_BF533, 0x0005,
b3187e24
BS
206 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315
207 | WA_LOAD_LCREGS | WA_05000074},
ea2382be 208 {"bf533", BFIN_CPU_BF533, 0x0004,
669eeb28 209 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
b3187e24
BS
210 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
211 | WA_05000074},
ea2382be 212 {"bf533", BFIN_CPU_BF533, 0x0003,
669eeb28 213 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
b3187e24
BS
214 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
215 | WA_05000074},
ea2382be
JZ
216
217 {"bf534", BFIN_CPU_BF534, 0x0003,
b3187e24 218 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074},
ea2382be 219 {"bf534", BFIN_CPU_BF534, 0x0002,
669eeb28 220 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
b3187e24
BS
221 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
222 | WA_05000074},
ea2382be 223 {"bf534", BFIN_CPU_BF534, 0x0001,
669eeb28 224 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
b3187e24
BS
225 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
226 | WA_05000074},
ea2382be
JZ
227
228 {"bf536", BFIN_CPU_BF536, 0x0003,
b3187e24 229 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074},
ea2382be 230 {"bf536", BFIN_CPU_BF536, 0x0002,
669eeb28 231 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
b3187e24
BS
232 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
233 | WA_05000074},
ea2382be 234 {"bf536", BFIN_CPU_BF536, 0x0001,
669eeb28 235 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
b3187e24
BS
236 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
237 | WA_05000074},
ea2382be
JZ
238
239 {"bf537", BFIN_CPU_BF537, 0x0003,
b3187e24 240 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074},
ea2382be 241 {"bf537", BFIN_CPU_BF537, 0x0002,
669eeb28 242 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
b3187e24
BS
243 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
244 | WA_05000074},
ea2382be 245 {"bf537", BFIN_CPU_BF537, 0x0001,
669eeb28 246 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
b3187e24
BS
247 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
248 | WA_05000074},
ea2382be 249
318b3009 250 {"bf538", BFIN_CPU_BF538, 0x0005,
b3187e24 251 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074},
ea2382be 252 {"bf538", BFIN_CPU_BF538, 0x0004,
b3187e24 253 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074},
ea2382be 254 {"bf538", BFIN_CPU_BF538, 0x0003,
669eeb28 255 WA_SPECULATIVE_LOADS | WA_RETS
b3187e24 256 | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS | WA_05000074},
a6340be1 257 {"bf538", BFIN_CPU_BF538, 0x0002,
97a988bc 258 WA_SPECULATIVE_LOADS | WA_RETS
b3187e24
BS
259 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
260 | WA_05000074},
ea2382be 261
318b3009 262 {"bf539", BFIN_CPU_BF539, 0x0005,
b3187e24 263 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074},
ea2382be 264 {"bf539", BFIN_CPU_BF539, 0x0004,
b3187e24 265 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074},
ea2382be 266 {"bf539", BFIN_CPU_BF539, 0x0003,
669eeb28 267 WA_SPECULATIVE_LOADS | WA_RETS
b3187e24 268 | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS | WA_05000074},
ea2382be 269 {"bf539", BFIN_CPU_BF539, 0x0002,
669eeb28 270 WA_SPECULATIVE_LOADS | WA_RETS
b3187e24
BS
271 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
272 | WA_05000074},
ea2382be 273
5254cd50 274 {"bf542m", BFIN_CPU_BF542M, 0x0003,
b3187e24 275 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
5254cd50 276
318b3009 277 {"bf542", BFIN_CPU_BF542, 0x0002,
b3187e24 278 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
a6340be1 279 {"bf542", BFIN_CPU_BF542, 0x0001,
b3187e24 280 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074},
ea2382be 281 {"bf542", BFIN_CPU_BF542, 0x0000,
b3187e24
BS
282 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS
283 | WA_05000074},
ea2382be 284
5254cd50 285 {"bf544m", BFIN_CPU_BF544M, 0x0003,
b3187e24 286 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
5254cd50 287
318b3009 288 {"bf544", BFIN_CPU_BF544, 0x0002,
b3187e24 289 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
a6340be1 290 {"bf544", BFIN_CPU_BF544, 0x0001,
b3187e24 291 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074},
ea2382be 292 {"bf544", BFIN_CPU_BF544, 0x0000,
b3187e24
BS
293 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS
294 | WA_05000074},
ea2382be 295
5254cd50 296 {"bf547m", BFIN_CPU_BF547M, 0x0003,
b3187e24 297 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
5254cd50 298
318b3009 299 {"bf547", BFIN_CPU_BF547, 0x0002,
b3187e24 300 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
a6340be1 301 {"bf547", BFIN_CPU_BF547, 0x0001,
b3187e24 302 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074},
64882649 303 {"bf547", BFIN_CPU_BF547, 0x0000,
b3187e24
BS
304 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS
305 | WA_05000074},
64882649 306
5254cd50 307 {"bf548m", BFIN_CPU_BF548M, 0x0003,
b3187e24 308 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
5254cd50 309
318b3009 310 {"bf548", BFIN_CPU_BF548, 0x0002,
b3187e24 311 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
a6340be1 312 {"bf548", BFIN_CPU_BF548, 0x0001,
b3187e24 313 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074},
ea2382be 314 {"bf548", BFIN_CPU_BF548, 0x0000,
b3187e24
BS
315 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS
316 | WA_05000074},
ea2382be 317
5254cd50 318 {"bf549m", BFIN_CPU_BF549M, 0x0003,
b3187e24 319 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
5254cd50 320
318b3009 321 {"bf549", BFIN_CPU_BF549, 0x0002,
b3187e24 322 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
a6340be1 323 {"bf549", BFIN_CPU_BF549, 0x0001,
b3187e24 324 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074},
ea2382be 325 {"bf549", BFIN_CPU_BF549, 0x0000,
b3187e24
BS
326 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS
327 | WA_05000074},
ea2382be 328
669eeb28 329 {"bf561", BFIN_CPU_BF561, 0x0005, WA_RETS
b3187e24 330 | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS | WA_05000074},
ea2382be 331 {"bf561", BFIN_CPU_BF561, 0x0003,
669eeb28 332 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
b3187e24
BS
333 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
334 | WA_05000074},
ea2382be 335 {"bf561", BFIN_CPU_BF561, 0x0002,
669eeb28 336 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
b3187e24
BS
337 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
338 | WA_05000074},
ea2382be 339
d3c176fc 340 {NULL, BFIN_CPU_UNKNOWN, 0, 0}
ea2382be
JZ
341};
342
97a988bc 343int splitting_for_sched, splitting_loops;
bbbc206e 344
0d4a78eb
BS
345static void
346bfin_globalize_label (FILE *stream, const char *name)
347{
348 fputs (".global ", stream);
349 assemble_name (stream, name);
350 fputc (';',stream);
351 fputc ('\n',stream);
352}
353
354static void
355output_file_start (void)
356{
357 FILE *file = asm_out_file;
358 int i;
359
bbbc206e
BS
360 /* Variable tracking should be run after all optimizations which change order
361 of insns. It also needs a valid CFG. This can't be done in
c5387660 362 bfin_option_override, because flag_var_tracking is finalized after
bbbc206e
BS
363 that. */
364 bfin_flag_var_tracking = flag_var_tracking;
365 flag_var_tracking = 0;
366
0d4a78eb
BS
367 fprintf (file, ".file \"%s\";\n", input_filename);
368
369 for (i = 0; arg_regs[i] >= 0; i++)
370 ;
371 max_arg_registers = i; /* how many arg reg used */
372}
373
0d4a78eb
BS
374/* Examine machine-dependent attributes of function type FUNTYPE and return its
375 type. See the definition of E_FUNKIND. */
376
3101faab
KG
377static e_funkind
378funkind (const_tree funtype)
0d4a78eb
BS
379{
380 tree attrs = TYPE_ATTRIBUTES (funtype);
381 if (lookup_attribute ("interrupt_handler", attrs))
382 return INTERRUPT_HANDLER;
383 else if (lookup_attribute ("exception_handler", attrs))
384 return EXCPT_HANDLER;
385 else if (lookup_attribute ("nmi_handler", attrs))
386 return NMI_HANDLER;
387 else
388 return SUBROUTINE;
389}
390\f
09350e36
BS
391/* Legitimize PIC addresses. If the address is already position-independent,
392 we return ORIG. Newly generated position-independent addresses go into a
393 reg. This is REG if nonzero, otherwise we allocate register(s) as
394 necessary. PICREG is the register holding the pointer to the PIC offset
395 table. */
396
6614f9f5 397static rtx
09350e36
BS
398legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
399{
400 rtx addr = orig;
0a2aaacc 401 rtx new_rtx = orig;
09350e36
BS
402
403 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
404 {
6b97a439
BS
405 int unspec;
406 rtx tmp;
407
408 if (TARGET_ID_SHARED_LIBRARY)
409 unspec = UNSPEC_MOVE_PIC;
410 else if (GET_CODE (addr) == SYMBOL_REF
411 && SYMBOL_REF_FUNCTION_P (addr))
412 unspec = UNSPEC_FUNCDESC_GOT17M4;
09350e36 413 else
6b97a439
BS
414 unspec = UNSPEC_MOVE_FDPIC;
415
416 if (reg == 0)
09350e36 417 {
b3a13419 418 gcc_assert (can_create_pseudo_p ());
6b97a439 419 reg = gen_reg_rtx (Pmode);
09350e36 420 }
6b97a439
BS
421
422 tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
0a2aaacc 423 new_rtx = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
6b97a439 424
0a2aaacc 425 emit_move_insn (reg, new_rtx);
09350e36 426 if (picreg == pic_offset_table_rtx)
e3b5732b 427 crtl->uses_pic_offset_table = 1;
09350e36
BS
428 return reg;
429 }
430
431 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
432 {
433 rtx base;
434
435 if (GET_CODE (addr) == CONST)
436 {
437 addr = XEXP (addr, 0);
438 gcc_assert (GET_CODE (addr) == PLUS);
439 }
440
441 if (XEXP (addr, 0) == picreg)
442 return orig;
443
444 if (reg == 0)
445 {
b3a13419 446 gcc_assert (can_create_pseudo_p ());
09350e36
BS
447 reg = gen_reg_rtx (Pmode);
448 }
449
450 base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
451 addr = legitimize_pic_address (XEXP (addr, 1),
452 base == reg ? NULL_RTX : reg,
453 picreg);
454
455 if (GET_CODE (addr) == CONST_INT)
456 {
457 gcc_assert (! reload_in_progress && ! reload_completed);
458 addr = force_reg (Pmode, addr);
459 }
460
461 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
462 {
463 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
464 addr = XEXP (addr, 1);
465 }
466
467 return gen_rtx_PLUS (Pmode, base, addr);
468 }
469
0a2aaacc 470 return new_rtx;
09350e36
BS
471}
472\f
0d4a78eb
BS
473/* Stack frame layout. */
474
4d82f261
BS
475/* For a given REGNO, determine whether it must be saved in the function
476 prologue. IS_INTHANDLER specifies whether we're generating a normal
477 prologue or an interrupt/exception one. */
478static bool
479must_save_p (bool is_inthandler, unsigned regno)
0d4a78eb 480{
4d82f261 481 if (D_REGNO_P (regno))
0d4a78eb 482 {
4d82f261 483 bool is_eh_return_reg = false;
e3b5732b 484 if (crtl->calls_eh_return)
0d4a78eb
BS
485 {
486 unsigned j;
487 for (j = 0; ; j++)
488 {
489 unsigned test = EH_RETURN_DATA_REGNO (j);
490 if (test == INVALID_REGNUM)
491 break;
4d82f261
BS
492 if (test == regno)
493 is_eh_return_reg = true;
0d4a78eb
BS
494 }
495 }
496
4d82f261
BS
497 return (is_eh_return_reg
498 || (df_regs_ever_live_p (regno)
499 && !fixed_regs[regno]
500 && (is_inthandler || !call_used_regs[regno])));
0d4a78eb 501 }
4d82f261
BS
502 else if (P_REGNO_P (regno))
503 {
504 return ((df_regs_ever_live_p (regno)
505 && !fixed_regs[regno]
506 && (is_inthandler || !call_used_regs[regno]))
669eeb28
BS
507 || (is_inthandler
508 && (ENABLE_WA_05000283 || ENABLE_WA_05000315)
509 && regno == REG_P5)
4d82f261
BS
510 || (!TARGET_FDPIC
511 && regno == PIC_OFFSET_TABLE_REGNUM
e3b5732b 512 && (crtl->uses_pic_offset_table
4d82f261
BS
513 || (TARGET_ID_SHARED_LIBRARY && !current_function_is_leaf))));
514 }
515 else
516 return ((is_inthandler || !call_used_regs[regno])
517 && (df_regs_ever_live_p (regno)
518 || (!leaf_function_p () && call_used_regs[regno])));
519
520}
521
522/* Compute the number of DREGS to save with a push_multiple operation.
523 This could include registers that aren't modified in the function,
524 since push_multiple only takes a range of registers.
525 If IS_INTHANDLER, then everything that is live must be saved, even
526 if normally call-clobbered.
527 If CONSECUTIVE, return the number of registers we can save in one
528 instruction with a push/pop multiple instruction. */
529
530static int
531n_dregs_to_save (bool is_inthandler, bool consecutive)
532{
533 int count = 0;
534 unsigned i;
535
536 for (i = REG_R7 + 1; i-- != REG_R0;)
537 {
538 if (must_save_p (is_inthandler, i))
539 count++;
540 else if (consecutive)
541 return count;
542 }
543 return count;
0d4a78eb
BS
544}
545
546/* Like n_dregs_to_save, but compute number of PREGS to save. */
547
548static int
4d82f261 549n_pregs_to_save (bool is_inthandler, bool consecutive)
0d4a78eb 550{
4d82f261 551 int count = 0;
0d4a78eb
BS
552 unsigned i;
553
4d82f261
BS
554 for (i = REG_P5 + 1; i-- != REG_P0;)
555 if (must_save_p (is_inthandler, i))
556 count++;
557 else if (consecutive)
558 return count;
559 return count;
0d4a78eb
BS
560}
561
562/* Determine if we are going to save the frame pointer in the prologue. */
563
564static bool
565must_save_fp_p (void)
566{
9840d30a
BS
567 return df_regs_ever_live_p (REG_FP);
568}
569
570/* Determine if we are going to save the RETS register. */
571static bool
572must_save_rets_p (void)
573{
574 return df_regs_ever_live_p (REG_RETS);
0d4a78eb
BS
575}
576
577static bool
578stack_frame_needed_p (void)
579{
580 /* EH return puts a new return address into the frame using an
581 address relative to the frame pointer. */
e3b5732b 582 if (crtl->calls_eh_return)
0d4a78eb
BS
583 return true;
584 return frame_pointer_needed;
585}
586
587/* Emit code to save registers in the prologue. SAVEALL is nonzero if we
588 must save all registers; this is used for interrupt handlers.
e989202f
BS
589 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
590 this for an interrupt (or exception) handler. */
0d4a78eb
BS
591
592static void
e989202f 593expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler)
0d4a78eb 594{
bf3f9581
BS
595 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
596 rtx predec = gen_rtx_MEM (SImode, predec1);
4d82f261
BS
597 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
598 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
599 int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
600 int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
601 int dregno, pregno;
602 int total_consec = ndregs_consec + npregs_consec;
603 int i, d_to_save;
0d4a78eb 604
bf3f9581
BS
605 if (saveall || is_inthandler)
606 {
4d82f261 607 rtx insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
a848cf52 608
bf3f9581 609 RTX_FRAME_RELATED_P (insn) = 1;
669eeb28
BS
610 for (dregno = REG_LT0; dregno <= REG_LB1; dregno++)
611 if (! current_function_is_leaf
612 || cfun->machine->has_hardware_loops
613 || cfun->machine->has_loopreg_clobber
614 || (ENABLE_WA_05000257
615 && (dregno == REG_LC0 || dregno == REG_LC1)))
a848cf52
BS
616 {
617 insn = emit_move_insn (predec, gen_rtx_REG (SImode, dregno));
618 RTX_FRAME_RELATED_P (insn) = 1;
619 }
bf3f9581
BS
620 }
621
4d82f261
BS
622 if (total_consec != 0)
623 {
624 rtx insn;
625 rtx val = GEN_INT (-total_consec * 4);
626 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 2));
627
628 XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
629 UNSPEC_PUSH_MULTIPLE);
630 XVECEXP (pat, 0, total_consec + 1) = gen_rtx_SET (VOIDmode, spreg,
631 gen_rtx_PLUS (Pmode,
632 spreg,
633 val));
634 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total_consec + 1)) = 1;
635 d_to_save = ndregs_consec;
636 dregno = REG_R7 + 1 - ndregs_consec;
637 pregno = REG_P5 + 1 - npregs_consec;
638 for (i = 0; i < total_consec; i++)
639 {
640 rtx memref = gen_rtx_MEM (word_mode,
641 gen_rtx_PLUS (Pmode, spreg,
642 GEN_INT (- i * 4 - 4)));
643 rtx subpat;
644 if (d_to_save > 0)
645 {
646 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
647 dregno++));
648 d_to_save--;
649 }
650 else
651 {
652 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
653 pregno++));
654 }
655 XVECEXP (pat, 0, i + 1) = subpat;
656 RTX_FRAME_RELATED_P (subpat) = 1;
657 }
658 insn = emit_insn (pat);
659 RTX_FRAME_RELATED_P (insn) = 1;
660 }
0d4a78eb 661
4d82f261 662 for (dregno = REG_R0; ndregs != ndregs_consec; dregno++)
0d4a78eb 663 {
4d82f261 664 if (must_save_p (is_inthandler, dregno))
0d4a78eb 665 {
4d82f261
BS
666 rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, dregno));
667 RTX_FRAME_RELATED_P (insn) = 1;
0d4a78eb
BS
668 ndregs--;
669 }
4d82f261
BS
670 }
671 for (pregno = REG_P0; npregs != npregs_consec; pregno++)
672 {
673 if (must_save_p (is_inthandler, pregno))
0d4a78eb 674 {
4d82f261
BS
675 rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, pregno));
676 RTX_FRAME_RELATED_P (insn) = 1;
677 npregs--;
0d4a78eb 678 }
0d4a78eb 679 }
bf3f9581
BS
680 for (i = REG_P7 + 1; i < REG_CC; i++)
681 if (saveall
682 || (is_inthandler
683 && (df_regs_ever_live_p (i)
684 || (!leaf_function_p () && call_used_regs[i]))))
685 {
4d82f261 686 rtx insn;
bf3f9581
BS
687 if (i == REG_A0 || i == REG_A1)
688 insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
689 gen_rtx_REG (PDImode, i));
690 else
691 insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
692 RTX_FRAME_RELATED_P (insn) = 1;
693 }
0d4a78eb
BS
694}
695
696/* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
697 must save all registers; this is used for interrupt handlers.
e989202f
BS
698 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
699 this for an interrupt (or exception) handler. */
0d4a78eb
BS
700
701static void
e989202f 702expand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler)
0d4a78eb 703{
bf3f9581
BS
704 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
705 rtx postinc = gen_rtx_MEM (SImode, postinc1);
706
4d82f261
BS
707 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
708 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
709 int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
710 int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
711 int total_consec = ndregs_consec + npregs_consec;
0d4a78eb 712 int i, regno;
4d82f261 713 rtx insn;
0d4a78eb 714
bf3f9581
BS
715 /* A slightly crude technique to stop flow from trying to delete "dead"
716 insns. */
717 MEM_VOLATILE_P (postinc) = 1;
718
719 for (i = REG_CC - 1; i > REG_P7; i--)
720 if (saveall
721 || (is_inthandler
722 && (df_regs_ever_live_p (i)
723 || (!leaf_function_p () && call_used_regs[i]))))
724 {
725 if (i == REG_A0 || i == REG_A1)
726 {
727 rtx mem = gen_rtx_MEM (PDImode, postinc1);
728 MEM_VOLATILE_P (mem) = 1;
729 emit_move_insn (gen_rtx_REG (PDImode, i), mem);
730 }
731 else
732 emit_move_insn (gen_rtx_REG (SImode, i), postinc);
733 }
734
4d82f261
BS
735 regno = REG_P5 - npregs_consec;
736 for (; npregs != npregs_consec; regno--)
0d4a78eb 737 {
4d82f261 738 if (must_save_p (is_inthandler, regno))
0d4a78eb 739 {
4d82f261
BS
740 emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
741 npregs--;
0d4a78eb
BS
742 }
743 }
4d82f261
BS
744 regno = REG_R7 - ndregs_consec;
745 for (; ndregs != ndregs_consec; regno--)
746 {
747 if (must_save_p (is_inthandler, regno))
748 {
749 emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
750 ndregs--;
751 }
752 }
753
754 if (total_consec != 0)
755 {
756 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 1));
757 XVECEXP (pat, 0, 0)
758 = gen_rtx_SET (VOIDmode, spreg,
759 gen_rtx_PLUS (Pmode, spreg,
760 GEN_INT (total_consec * 4)));
761
762 if (npregs_consec > 0)
763 regno = REG_P5 + 1;
764 else
765 regno = REG_R7 + 1;
0d4a78eb 766
4d82f261
BS
767 for (i = 0; i < total_consec; i++)
768 {
769 rtx addr = (i > 0
770 ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
771 : spreg);
772 rtx memref = gen_rtx_MEM (word_mode, addr);
773
774 regno--;
775 XVECEXP (pat, 0, i + 1)
776 = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
777
778 if (npregs_consec > 0)
779 {
780 if (--npregs_consec == 0)
781 regno = REG_R7 + 1;
782 }
783 }
bf3f9581 784
4d82f261
BS
785 insn = emit_insn (pat);
786 RTX_FRAME_RELATED_P (insn) = 1;
787 }
bf3f9581 788 if (saveall || is_inthandler)
a848cf52 789 {
669eeb28
BS
790 for (regno = REG_LB1; regno >= REG_LT0; regno--)
791 if (! current_function_is_leaf
792 || cfun->machine->has_hardware_loops
793 || cfun->machine->has_loopreg_clobber
794 || (ENABLE_WA_05000257 && (regno == REG_LC0 || regno == REG_LC1)))
a848cf52
BS
795 emit_move_insn (gen_rtx_REG (SImode, regno), postinc);
796
797 emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
798 }
0d4a78eb
BS
799}
800
801/* Perform any needed actions needed for a function that is receiving a
802 variable number of arguments.
803
804 CUM is as above.
805
806 MODE and TYPE are the mode and type of the current parameter.
807
808 PRETEND_SIZE is a variable that should be set to the amount of stack
809 that must be pushed by the prolog to pretend that our caller pushed
810 it.
811
812 Normally, this macro will push all remaining incoming registers on the
813 stack and set PRETEND_SIZE to the length of the registers pushed.
814
815 Blackfin specific :
816 - VDSP C compiler manual (our ABI) says that a variable args function
817 should save the R0, R1 and R2 registers in the stack.
818 - The caller will always leave space on the stack for the
819 arguments that are passed in registers, so we dont have
820 to leave any extra space.
821 - now, the vastart pointer can access all arguments from the stack. */
822
823static void
824setup_incoming_varargs (CUMULATIVE_ARGS *cum,
825 enum machine_mode mode ATTRIBUTE_UNUSED,
826 tree type ATTRIBUTE_UNUSED, int *pretend_size,
827 int no_rtl)
828{
829 rtx mem;
830 int i;
831
832 if (no_rtl)
833 return;
834
835 /* The move for named arguments will be generated automatically by the
836 compiler. We need to generate the move rtx for the unnamed arguments
f652d14b 837 if they are in the first 3 words. We assume at least 1 named argument
0d4a78eb
BS
838 exists, so we never generate [ARGP] = R0 here. */
839
840 for (i = cum->words + 1; i < max_arg_registers; i++)
841 {
842 mem = gen_rtx_MEM (Pmode,
843 plus_constant (arg_pointer_rtx, (i * UNITS_PER_WORD)));
844 emit_move_insn (mem, gen_rtx_REG (Pmode, i));
845 }
846
847 *pretend_size = 0;
848}
849
850/* Value should be nonzero if functions must have frame pointers.
851 Zero means the frame pointer need not be set up (and parms may
852 be accessed via the stack pointer) in functions that seem suitable. */
853
b52b1749 854static bool
0d4a78eb
BS
855bfin_frame_pointer_required (void)
856{
857 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
858
859 if (fkind != SUBROUTINE)
b52b1749 860 return true;
0d4a78eb 861
a4d05547 862 /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
0d4a78eb
BS
863 so we have to override it for non-leaf functions. */
864 if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf)
b52b1749 865 return true;
0d4a78eb 866
b52b1749 867 return false;
0d4a78eb
BS
868}
869
870/* Return the number of registers pushed during the prologue. */
871
872static int
873n_regs_saved_by_prologue (void)
874{
875 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
e989202f
BS
876 bool is_inthandler = fkind != SUBROUTINE;
877 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
878 bool all = (lookup_attribute ("saveall", attrs) != NULL_TREE
879 || (is_inthandler && !current_function_is_leaf));
4d82f261
BS
880 int ndregs = all ? 8 : n_dregs_to_save (is_inthandler, false);
881 int npregs = all ? 6 : n_pregs_to_save (is_inthandler, false);
e989202f 882 int n = ndregs + npregs;
bf3f9581 883 int i;
0d4a78eb 884
e989202f 885 if (all || stack_frame_needed_p ())
0d4a78eb
BS
886 n += 2;
887 else
888 {
889 if (must_save_fp_p ())
890 n++;
9840d30a 891 if (must_save_rets_p ())
0d4a78eb
BS
892 n++;
893 }
894
bf3f9581 895 if (fkind != SUBROUTINE || all)
a848cf52
BS
896 {
897 /* Increment once for ASTAT. */
898 n++;
899 if (! current_function_is_leaf
900 || cfun->machine->has_hardware_loops
901 || cfun->machine->has_loopreg_clobber)
902 {
903 n += 6;
904 }
905 }
bf3f9581 906
0d4a78eb
BS
907 if (fkind != SUBROUTINE)
908 {
0d4a78eb
BS
909 /* RETE/X/N. */
910 if (lookup_attribute ("nesting", attrs))
911 n++;
0d4a78eb 912 }
bf3f9581
BS
913
914 for (i = REG_P7 + 1; i < REG_CC; i++)
915 if (all
916 || (fkind != SUBROUTINE
917 && (df_regs_ever_live_p (i)
918 || (!leaf_function_p () && call_used_regs[i]))))
919 n += i == REG_A0 || i == REG_A1 ? 2 : 1;
920
0d4a78eb
BS
921 return n;
922}
923
7b5cbb57
AS
924/* Given FROM and TO register numbers, say whether this elimination is
925 allowed. Frame pointer elimination is automatically handled.
926
927 All other eliminations are valid. */
928
929static bool
930bfin_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
931{
932 return (to == STACK_POINTER_REGNUM ? ! frame_pointer_needed : true);
933}
934
0d4a78eb
BS
935/* Return the offset between two registers, one to be eliminated, and the other
936 its replacement, at the start of a routine. */
937
938HOST_WIDE_INT
939bfin_initial_elimination_offset (int from, int to)
940{
941 HOST_WIDE_INT offset = 0;
942
943 if (from == ARG_POINTER_REGNUM)
944 offset = n_regs_saved_by_prologue () * 4;
945
946 if (to == STACK_POINTER_REGNUM)
947 {
38173d38
JH
948 if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
949 offset += crtl->outgoing_args_size;
950 else if (crtl->outgoing_args_size)
0d4a78eb
BS
951 offset += FIXED_STACK_AREA;
952
953 offset += get_frame_size ();
954 }
955
956 return offset;
957}
958
959/* Emit code to load a constant CONSTANT into register REG; setting
09350e36
BS
960 RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
961 Make sure that the insns we generate need not be split. */
0d4a78eb
BS
962
963static void
09350e36 964frame_related_constant_load (rtx reg, HOST_WIDE_INT constant, bool related)
0d4a78eb
BS
965{
966 rtx insn;
967 rtx cst = GEN_INT (constant);
968
969 if (constant >= -32768 && constant < 65536)
970 insn = emit_move_insn (reg, cst);
971 else
972 {
973 /* We don't call split_load_immediate here, since dwarf2out.c can get
974 confused about some of the more clever sequences it can generate. */
975 insn = emit_insn (gen_movsi_high (reg, cst));
09350e36
BS
976 if (related)
977 RTX_FRAME_RELATED_P (insn) = 1;
0d4a78eb
BS
978 insn = emit_insn (gen_movsi_low (reg, reg, cst));
979 }
09350e36
BS
980 if (related)
981 RTX_FRAME_RELATED_P (insn) = 1;
0d4a78eb
BS
982}
983
1f9e4ca1
JZ
984/* Generate efficient code to add a value to a P register.
985 Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero.
986 EPILOGUE_P is zero if this function is called for prologue,
987 otherwise it's nonzero. And it's less than zero if this is for
988 sibcall epilogue. */
0d4a78eb
BS
989
990static void
1f9e4ca1 991add_to_reg (rtx reg, HOST_WIDE_INT value, int frame, int epilogue_p)
0d4a78eb
BS
992{
993 if (value == 0)
994 return;
995
996 /* Choose whether to use a sequence using a temporary register, or
942fd98f 997 a sequence with multiple adds. We can add a signed 7-bit value
0d4a78eb
BS
998 in one instruction. */
999 if (value > 120 || value < -120)
1000 {
1f9e4ca1
JZ
1001 rtx tmpreg;
1002 rtx tmpreg2;
0d4a78eb
BS
1003 rtx insn;
1004
1f9e4ca1
JZ
1005 tmpreg2 = NULL_RTX;
1006
1007 /* For prologue or normal epilogue, P1 can be safely used
1008 as the temporary register. For sibcall epilogue, we try to find
1009 a call used P register, which will be restored in epilogue.
1010 If we cannot find such a P register, we have to use one I register
1011 to help us. */
1012
1013 if (epilogue_p >= 0)
1014 tmpreg = gen_rtx_REG (SImode, REG_P1);
1015 else
1016 {
1017 int i;
1018 for (i = REG_P0; i <= REG_P5; i++)
b18e284e 1019 if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
1f9e4ca1
JZ
1020 || (!TARGET_FDPIC
1021 && i == PIC_OFFSET_TABLE_REGNUM
e3b5732b 1022 && (crtl->uses_pic_offset_table
1f9e4ca1
JZ
1023 || (TARGET_ID_SHARED_LIBRARY
1024 && ! current_function_is_leaf))))
1025 break;
1026 if (i <= REG_P5)
1027 tmpreg = gen_rtx_REG (SImode, i);
1028 else
1029 {
1030 tmpreg = gen_rtx_REG (SImode, REG_P1);
1031 tmpreg2 = gen_rtx_REG (SImode, REG_I0);
1032 emit_move_insn (tmpreg2, tmpreg);
1033 }
1034 }
1035
0d4a78eb 1036 if (frame)
09350e36 1037 frame_related_constant_load (tmpreg, value, TRUE);
0d4a78eb 1038 else
d6eb07dc 1039 insn = emit_move_insn (tmpreg, GEN_INT (value));
0d4a78eb 1040
d6eb07dc 1041 insn = emit_insn (gen_addsi3 (reg, reg, tmpreg));
0d4a78eb
BS
1042 if (frame)
1043 RTX_FRAME_RELATED_P (insn) = 1;
1f9e4ca1
JZ
1044
1045 if (tmpreg2 != NULL_RTX)
1046 emit_move_insn (tmpreg, tmpreg2);
0d4a78eb
BS
1047 }
1048 else
1049 do
1050 {
1051 int size = value;
1052 rtx insn;
1053
1054 if (size > 60)
1055 size = 60;
1056 else if (size < -60)
1057 /* We could use -62, but that would leave the stack unaligned, so
1058 it's no good. */
1059 size = -60;
1060
d6eb07dc 1061 insn = emit_insn (gen_addsi3 (reg, reg, GEN_INT (size)));
0d4a78eb
BS
1062 if (frame)
1063 RTX_FRAME_RELATED_P (insn) = 1;
1064 value -= size;
1065 }
1066 while (value != 0);
1067}
1068
1069/* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant
1070 is too large, generate a sequence of insns that has the same effect.
1071 SPREG contains (reg:SI REG_SP). */
1072
1073static void
1074emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size)
1075{
1076 HOST_WIDE_INT link_size = frame_size;
1077 rtx insn;
1078 int i;
1079
1080 if (link_size > 262140)
1081 link_size = 262140;
1082
1083 /* Use a LINK insn with as big a constant as possible, then subtract
1084 any remaining size from the SP. */
1085 insn = emit_insn (gen_link (GEN_INT (-8 - link_size)));
1086 RTX_FRAME_RELATED_P (insn) = 1;
1087
1088 for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
1089 {
1090 rtx set = XVECEXP (PATTERN (insn), 0, i);
3b9dd769 1091 gcc_assert (GET_CODE (set) == SET);
0d4a78eb
BS
1092 RTX_FRAME_RELATED_P (set) = 1;
1093 }
1094
1095 frame_size -= link_size;
1096
1097 if (frame_size > 0)
1098 {
1099 /* Must use a call-clobbered PREG that isn't the static chain. */
1100 rtx tmpreg = gen_rtx_REG (Pmode, REG_P1);
1101
09350e36 1102 frame_related_constant_load (tmpreg, -frame_size, TRUE);
0d4a78eb
BS
1103 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
1104 RTX_FRAME_RELATED_P (insn) = 1;
1105 }
1106}
1107
1108/* Return the number of bytes we must reserve for outgoing arguments
1109 in the current function's stack frame. */
1110
1111static HOST_WIDE_INT
1112arg_area_size (void)
1113{
38173d38 1114 if (crtl->outgoing_args_size)
0d4a78eb 1115 {
38173d38
JH
1116 if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
1117 return crtl->outgoing_args_size;
0d4a78eb
BS
1118 else
1119 return FIXED_STACK_AREA;
1120 }
1121 return 0;
1122}
1123
e989202f
BS
1124/* Save RETS and FP, and allocate a stack frame. ALL is true if the
1125 function must save all its registers (true only for certain interrupt
1126 handlers). */
0d4a78eb
BS
1127
1128static void
e989202f 1129do_link (rtx spreg, HOST_WIDE_INT frame_size, bool all)
0d4a78eb
BS
1130{
1131 frame_size += arg_area_size ();
1132
9840d30a
BS
1133 if (all
1134 || stack_frame_needed_p ()
1135 || (must_save_rets_p () && must_save_fp_p ()))
0d4a78eb
BS
1136 emit_link_insn (spreg, frame_size);
1137 else
1138 {
9840d30a 1139 if (must_save_rets_p ())
0d4a78eb
BS
1140 {
1141 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
1142 gen_rtx_PRE_DEC (Pmode, spreg)),
1143 bfin_rets_rtx);
1144 rtx insn = emit_insn (pat);
1145 RTX_FRAME_RELATED_P (insn) = 1;
1146 }
1147 if (must_save_fp_p ())
1148 {
1149 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
1150 gen_rtx_PRE_DEC (Pmode, spreg)),
1151 gen_rtx_REG (Pmode, REG_FP));
1152 rtx insn = emit_insn (pat);
1153 RTX_FRAME_RELATED_P (insn) = 1;
1154 }
1f9e4ca1 1155 add_to_reg (spreg, -frame_size, 1, 0);
0d4a78eb
BS
1156 }
1157}
1158
1f9e4ca1
JZ
1159/* Like do_link, but used for epilogues to deallocate the stack frame.
1160 EPILOGUE_P is zero if this function is called for prologue,
1161 otherwise it's nonzero. And it's less than zero if this is for
1162 sibcall epilogue. */
0d4a78eb
BS
1163
1164static void
1f9e4ca1 1165do_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all, int epilogue_p)
0d4a78eb
BS
1166{
1167 frame_size += arg_area_size ();
1168
9840d30a 1169 if (stack_frame_needed_p ())
0d4a78eb
BS
1170 emit_insn (gen_unlink ());
1171 else
1172 {
1173 rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg));
1174
1f9e4ca1 1175 add_to_reg (spreg, frame_size, 0, epilogue_p);
9840d30a 1176 if (all || must_save_fp_p ())
0d4a78eb
BS
1177 {
1178 rtx fpreg = gen_rtx_REG (Pmode, REG_FP);
1179 emit_move_insn (fpreg, postinc);
c41c1387 1180 emit_use (fpreg);
0d4a78eb 1181 }
9840d30a 1182 if (all || must_save_rets_p ())
0d4a78eb
BS
1183 {
1184 emit_move_insn (bfin_rets_rtx, postinc);
c41c1387 1185 emit_use (bfin_rets_rtx);
0d4a78eb
BS
1186 }
1187 }
1188}
1189
1190/* Generate a prologue suitable for a function of kind FKIND. This is
1191 called for interrupt and exception handler prologues.
1192 SPREG contains (reg:SI REG_SP). */
1193
1194static void
bf3f9581 1195expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind, bool all)
0d4a78eb 1196{
0d4a78eb
BS
1197 HOST_WIDE_INT frame_size = get_frame_size ();
1198 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
1199 rtx predec = gen_rtx_MEM (SImode, predec1);
1200 rtx insn;
1201 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
0d4a78eb
BS
1202 tree kspisusp = lookup_attribute ("kspisusp", attrs);
1203
1204 if (kspisusp)
1205 {
1206 insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP));
1207 RTX_FRAME_RELATED_P (insn) = 1;
1208 }
1209
1210 /* We need space on the stack in case we need to save the argument
1211 registers. */
1212 if (fkind == EXCPT_HANDLER)
1213 {
1214 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12)));
1215 RTX_FRAME_RELATED_P (insn) = 1;
1216 }
1217
e989202f
BS
1218 /* If we're calling other functions, they won't save their call-clobbered
1219 registers, so we must save everything here. */
1220 if (!current_function_is_leaf)
1221 all = true;
1222 expand_prologue_reg_save (spreg, all, true);
0d4a78eb 1223
669eeb28
BS
1224 if (ENABLE_WA_05000283 || ENABLE_WA_05000315)
1225 {
1226 rtx chipid = GEN_INT (trunc_int_for_mode (0xFFC00014, SImode));
1227 rtx p5reg = gen_rtx_REG (Pmode, REG_P5);
1228 emit_insn (gen_movbi (bfin_cc_rtx, const1_rtx));
1229 emit_insn (gen_movsi_high (p5reg, chipid));
1230 emit_insn (gen_movsi_low (p5reg, p5reg, chipid));
1231 emit_insn (gen_dummy_load (p5reg, bfin_cc_rtx));
1232 }
1233
0d4a78eb
BS
1234 if (lookup_attribute ("nesting", attrs))
1235 {
9840d30a 1236 rtx srcreg = gen_rtx_REG (Pmode, ret_regs[fkind]);
0d4a78eb
BS
1237 insn = emit_move_insn (predec, srcreg);
1238 RTX_FRAME_RELATED_P (insn) = 1;
1239 }
1240
e989202f 1241 do_link (spreg, frame_size, all);
0d4a78eb
BS
1242
1243 if (fkind == EXCPT_HANDLER)
1244 {
1245 rtx r0reg = gen_rtx_REG (SImode, REG_R0);
1246 rtx r1reg = gen_rtx_REG (SImode, REG_R1);
1247 rtx r2reg = gen_rtx_REG (SImode, REG_R2);
0d4a78eb 1248
d3c176fc
JR
1249 emit_move_insn (r0reg, gen_rtx_REG (SImode, REG_SEQSTAT));
1250 emit_insn (gen_ashrsi3 (r0reg, r0reg, GEN_INT (26)));
1251 emit_insn (gen_ashlsi3 (r0reg, r0reg, GEN_INT (26)));
1252 emit_move_insn (r1reg, spreg);
1253 emit_move_insn (r2reg, gen_rtx_REG (Pmode, REG_FP));
1254 emit_insn (gen_addsi3 (r2reg, r2reg, GEN_INT (8)));
0d4a78eb
BS
1255 }
1256}
1257
1258/* Generate an epilogue suitable for a function of kind FKIND. This is
1259 called for interrupt and exception handler epilogues.
1260 SPREG contains (reg:SI REG_SP). */
1261
1262static void
bf3f9581 1263expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind, bool all)
0d4a78eb 1264{
bf3f9581 1265 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
0d4a78eb
BS
1266 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
1267 rtx postinc = gen_rtx_MEM (SImode, postinc1);
0d4a78eb
BS
1268
1269 /* A slightly crude technique to stop flow from trying to delete "dead"
1270 insns. */
1271 MEM_VOLATILE_P (postinc) = 1;
1272
1f9e4ca1 1273 do_unlink (spreg, get_frame_size (), all, 1);
0d4a78eb
BS
1274
1275 if (lookup_attribute ("nesting", attrs))
1276 {
9840d30a 1277 rtx srcreg = gen_rtx_REG (Pmode, ret_regs[fkind]);
0d4a78eb
BS
1278 emit_move_insn (srcreg, postinc);
1279 }
1280
e989202f
BS
1281 /* If we're calling other functions, they won't save their call-clobbered
1282 registers, so we must save (and restore) everything here. */
1283 if (!current_function_is_leaf)
1284 all = true;
1285
e989202f 1286 expand_epilogue_reg_restore (spreg, all, true);
0d4a78eb 1287
0d4a78eb
BS
1288 /* Deallocate any space we left on the stack in case we needed to save the
1289 argument registers. */
1290 if (fkind == EXCPT_HANDLER)
1291 emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12)));
1292
9840d30a 1293 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, ret_regs[fkind])));
0d4a78eb
BS
1294}
1295
09350e36
BS
1296/* Used while emitting the prologue to generate code to load the correct value
1297 into the PIC register, which is passed in DEST. */
1298
9fc023cc 1299static rtx
09350e36
BS
1300bfin_load_pic_reg (rtx dest)
1301{
9fc023cc 1302 struct cgraph_local_info *i = NULL;
d3c176fc 1303 rtx addr;
9fc023cc 1304
7e8b322a 1305 i = cgraph_local_info (current_function_decl);
9fc023cc
BS
1306
1307 /* Functions local to the translation unit don't need to reload the
1308 pic reg, since the caller always passes a usable one. */
1309 if (i && i->local)
1310 return pic_offset_table_rtx;
09350e36
BS
1311
1312 if (bfin_lib_id_given)
1313 addr = plus_constant (pic_offset_table_rtx, -4 - bfin_library_id * 4);
1314 else
1315 addr = gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
1316 gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
1317 UNSPEC_LIBRARY_OFFSET));
d3c176fc 1318 emit_insn (gen_movsi (dest, gen_rtx_MEM (Pmode, addr)));
9fc023cc 1319 return dest;
09350e36
BS
1320}
1321
0d4a78eb
BS
1322/* Generate RTL for the prologue of the current function. */
1323
1324void
1325bfin_expand_prologue (void)
1326{
0d4a78eb
BS
1327 HOST_WIDE_INT frame_size = get_frame_size ();
1328 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
1329 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
09350e36 1330 rtx pic_reg_loaded = NULL_RTX;
bf3f9581
BS
1331 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1332 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
0d4a78eb
BS
1333
1334 if (fkind != SUBROUTINE)
1335 {
bf3f9581 1336 expand_interrupt_handler_prologue (spreg, fkind, all);
0d4a78eb
BS
1337 return;
1338 }
1339
e3b5732b 1340 if (crtl->limit_stack
3b62f0e1
BS
1341 || (TARGET_STACK_CHECK_L1
1342 && !DECL_NO_LIMIT_STACK (current_function_decl)))
09350e36
BS
1343 {
1344 HOST_WIDE_INT offset
1345 = bfin_initial_elimination_offset (ARG_POINTER_REGNUM,
1346 STACK_POINTER_REGNUM);
e3b5732b 1347 rtx lim = crtl->limit_stack ? stack_limit_rtx : NULL_RTX;
d6eb07dc 1348 rtx p2reg = gen_rtx_REG (Pmode, REG_P2);
09350e36 1349
d6eb07dc
BS
1350 if (!lim)
1351 {
d6eb07dc
BS
1352 emit_move_insn (p2reg, gen_int_mode (0xFFB00000, SImode));
1353 emit_move_insn (p2reg, gen_rtx_MEM (Pmode, p2reg));
1354 lim = p2reg;
1355 }
09350e36
BS
1356 if (GET_CODE (lim) == SYMBOL_REF)
1357 {
09350e36
BS
1358 if (TARGET_ID_SHARED_LIBRARY)
1359 {
1360 rtx p1reg = gen_rtx_REG (Pmode, REG_P1);
09350e36 1361 rtx val;
9fc023cc
BS
1362 pic_reg_loaded = bfin_load_pic_reg (p2reg);
1363 val = legitimize_pic_address (stack_limit_rtx, p1reg,
1364 pic_reg_loaded);
09350e36
BS
1365 emit_move_insn (p1reg, val);
1366 frame_related_constant_load (p2reg, offset, FALSE);
1367 emit_insn (gen_addsi3 (p2reg, p2reg, p1reg));
1368 lim = p2reg;
1369 }
1370 else
1371 {
d6eb07dc 1372 rtx limit = plus_constant (lim, offset);
09350e36
BS
1373 emit_move_insn (p2reg, limit);
1374 lim = p2reg;
1375 }
1376 }
d6eb07dc
BS
1377 else
1378 {
1379 if (lim != p2reg)
1380 emit_move_insn (p2reg, lim);
1f9e4ca1 1381 add_to_reg (p2reg, offset, 0, 0);
d6eb07dc
BS
1382 lim = p2reg;
1383 }
09350e36
BS
1384 emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim));
1385 emit_insn (gen_trapifcc ());
1386 }
bf3f9581 1387 expand_prologue_reg_save (spreg, all, false);
0d4a78eb 1388
8be6ada8 1389 do_link (spreg, frame_size, all);
0d4a78eb
BS
1390
1391 if (TARGET_ID_SHARED_LIBRARY
93147119 1392 && !TARGET_SEP_DATA
e3b5732b 1393 && (crtl->uses_pic_offset_table
0d4a78eb 1394 || !current_function_is_leaf))
09350e36 1395 bfin_load_pic_reg (pic_offset_table_rtx);
0d4a78eb
BS
1396}
1397
1398/* Generate RTL for the epilogue of the current function. NEED_RETURN is zero
1399 if this is for a sibcall. EH_RETURN is nonzero if we're expanding an
1f9e4ca1
JZ
1400 eh_return pattern. SIBCALL_P is true if this is a sibcall epilogue,
1401 false otherwise. */
0d4a78eb
BS
1402
1403void
1f9e4ca1 1404bfin_expand_epilogue (int need_return, int eh_return, bool sibcall_p)
0d4a78eb
BS
1405{
1406 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
1407 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
1f9e4ca1 1408 int e = sibcall_p ? -1 : 1;
bf3f9581
BS
1409 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1410 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
0d4a78eb
BS
1411
1412 if (fkind != SUBROUTINE)
1413 {
bf3f9581 1414 expand_interrupt_handler_epilogue (spreg, fkind, all);
0d4a78eb
BS
1415 return;
1416 }
1417
8be6ada8 1418 do_unlink (spreg, get_frame_size (), all, e);
0d4a78eb 1419
bf3f9581 1420 expand_epilogue_reg_restore (spreg, all, false);
0d4a78eb
BS
1421
1422 /* Omit the return insn if this is for a sibcall. */
1423 if (! need_return)
1424 return;
1425
1426 if (eh_return)
1427 emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2)));
1428
9840d30a 1429 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, REG_RETS)));
0d4a78eb
BS
1430}
1431\f
1432/* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
1433
1434int
1435bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
1436 unsigned int new_reg)
1437{
1438 /* Interrupt functions can only use registers that have already been
1439 saved by the prologue, even if they would normally be
1440 call-clobbered. */
1441
1442 if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE
6fb5fa3c 1443 && !df_regs_ever_live_p (new_reg))
0d4a78eb
BS
1444 return 0;
1445
1446 return 1;
1447}
1448
1449/* Return the value of the return address for the frame COUNT steps up
1450 from the current frame, after the prologue.
1451 We punt for everything but the current frame by returning const0_rtx. */
1452
1453rtx
1454bfin_return_addr_rtx (int count)
1455{
1456 if (count != 0)
1457 return const0_rtx;
1458
1459 return get_hard_reg_initial_val (Pmode, REG_RETS);
1460}
1461
54aefc36
JZ
1462static rtx
1463bfin_delegitimize_address (rtx orig_x)
1464{
266d11d8 1465 rtx x = orig_x;
54aefc36
JZ
1466
1467 if (GET_CODE (x) != MEM)
1468 return orig_x;
1469
1470 x = XEXP (x, 0);
1471 if (GET_CODE (x) == PLUS
1472 && GET_CODE (XEXP (x, 1)) == UNSPEC
1473 && XINT (XEXP (x, 1), 1) == UNSPEC_MOVE_PIC
1474 && GET_CODE (XEXP (x, 0)) == REG
1475 && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM)
1476 return XVECEXP (XEXP (x, 1), 0, 0);
1477
1478 return orig_x;
1479}
1480
0d4a78eb
BS
1481/* This predicate is used to compute the length of a load/store insn.
1482 OP is a MEM rtx, we return nonzero if its addressing mode requires a
942fd98f 1483 32-bit instruction. */
0d4a78eb
BS
1484
1485int
1486effective_address_32bit_p (rtx op, enum machine_mode mode)
1487{
1488 HOST_WIDE_INT offset;
1489
1490 mode = GET_MODE (op);
1491 op = XEXP (op, 0);
1492
0d4a78eb 1493 if (GET_CODE (op) != PLUS)
3b9dd769
NS
1494 {
1495 gcc_assert (REG_P (op) || GET_CODE (op) == POST_INC
1496 || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC);
1497 return 0;
1498 }
0d4a78eb 1499
96f46444
BS
1500 if (GET_CODE (XEXP (op, 1)) == UNSPEC)
1501 return 1;
1502
0d4a78eb
BS
1503 offset = INTVAL (XEXP (op, 1));
1504
942fd98f 1505 /* All byte loads use a 16-bit offset. */
0d4a78eb
BS
1506 if (GET_MODE_SIZE (mode) == 1)
1507 return 1;
1508
1509 if (GET_MODE_SIZE (mode) == 4)
1510 {
1511 /* Frame pointer relative loads can use a negative offset, all others
1512 are restricted to a small positive one. */
1513 if (XEXP (op, 0) == frame_pointer_rtx)
1514 return offset < -128 || offset > 60;
1515 return offset < 0 || offset > 60;
1516 }
1517
1518 /* Must be HImode now. */
1519 return offset < 0 || offset > 30;
1520}
1521
c4963a0a
BS
1522/* Returns true if X is a memory reference using an I register. */
1523bool
1524bfin_dsp_memref_p (rtx x)
1525{
1526 if (! MEM_P (x))
1527 return false;
1528 x = XEXP (x, 0);
1529 if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_INC
1530 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_DEC)
1531 x = XEXP (x, 0);
1532 return IREG_P (x);
1533}
1534
0d4a78eb
BS
1535/* Return cost of the memory address ADDR.
1536 All addressing modes are equally cheap on the Blackfin. */
1537
1538static int
f40751dd 1539bfin_address_cost (rtx addr ATTRIBUTE_UNUSED, bool speed ATTRIBUTE_UNUSED)
0d4a78eb
BS
1540{
1541 return 1;
1542}
1543
1544/* Subroutine of print_operand; used to print a memory reference X to FILE. */
1545
1546void
1547print_address_operand (FILE *file, rtx x)
1548{
0d4a78eb
BS
1549 switch (GET_CODE (x))
1550 {
1551 case PLUS:
1552 output_address (XEXP (x, 0));
1553 fprintf (file, "+");
1554 output_address (XEXP (x, 1));
1555 break;
1556
1557 case PRE_DEC:
1558 fprintf (file, "--");
1559 output_address (XEXP (x, 0));
1560 break;
1561 case POST_INC:
1562 output_address (XEXP (x, 0));
1563 fprintf (file, "++");
1564 break;
1565 case POST_DEC:
1566 output_address (XEXP (x, 0));
1567 fprintf (file, "--");
1568 break;
1569
1570 default:
3b9dd769 1571 gcc_assert (GET_CODE (x) != MEM);
0d4a78eb 1572 print_operand (file, x, 0);
3b9dd769 1573 break;
0d4a78eb
BS
1574 }
1575}
1576
1577/* Adding intp DImode support by Tony
1578 * -- Q: (low word)
1579 * -- R: (high word)
1580 */
1581
1582void
1583print_operand (FILE *file, rtx x, char code)
1584{
bbbc206e
BS
1585 enum machine_mode mode;
1586
1587 if (code == '!')
1588 {
1589 if (GET_MODE (current_output_insn) == SImode)
1590 fprintf (file, " ||");
1591 else
1592 fprintf (file, ";");
1593 return;
1594 }
1595
1596 mode = GET_MODE (x);
0d4a78eb
BS
1597
1598 switch (code)
1599 {
1600 case 'j':
1601 switch (GET_CODE (x))
1602 {
1603 case EQ:
1604 fprintf (file, "e");
1605 break;
1606 case NE:
1607 fprintf (file, "ne");
1608 break;
1609 case GT:
1610 fprintf (file, "g");
1611 break;
1612 case LT:
1613 fprintf (file, "l");
1614 break;
1615 case GE:
1616 fprintf (file, "ge");
1617 break;
1618 case LE:
1619 fprintf (file, "le");
1620 break;
1621 case GTU:
1622 fprintf (file, "g");
1623 break;
1624 case LTU:
1625 fprintf (file, "l");
1626 break;
1627 case GEU:
1628 fprintf (file, "ge");
1629 break;
1630 case LEU:
1631 fprintf (file, "le");
1632 break;
1633 default:
1634 output_operand_lossage ("invalid %%j value");
1635 }
1636 break;
1637
1638 case 'J': /* reverse logic */
1639 switch (GET_CODE(x))
1640 {
1641 case EQ:
1642 fprintf (file, "ne");
1643 break;
1644 case NE:
1645 fprintf (file, "e");
1646 break;
1647 case GT:
1648 fprintf (file, "le");
1649 break;
1650 case LT:
1651 fprintf (file, "ge");
1652 break;
1653 case GE:
1654 fprintf (file, "l");
1655 break;
1656 case LE:
1657 fprintf (file, "g");
1658 break;
1659 case GTU:
1660 fprintf (file, "le");
1661 break;
1662 case LTU:
1663 fprintf (file, "ge");
1664 break;
1665 case GEU:
1666 fprintf (file, "l");
1667 break;
1668 case LEU:
1669 fprintf (file, "g");
1670 break;
1671 default:
1672 output_operand_lossage ("invalid %%J value");
1673 }
1674 break;
1675
1676 default:
1677 switch (GET_CODE (x))
1678 {
1679 case REG:
1680 if (code == 'h')
1681 {
b570063a
JZ
1682 if (REGNO (x) < 32)
1683 fprintf (file, "%s", short_reg_names[REGNO (x)]);
1684 else
1685 output_operand_lossage ("invalid operand for code '%c'", code);
0d4a78eb
BS
1686 }
1687 else if (code == 'd')
1688 {
b570063a
JZ
1689 if (REGNO (x) < 32)
1690 fprintf (file, "%s", high_reg_names[REGNO (x)]);
1691 else
1692 output_operand_lossage ("invalid operand for code '%c'", code);
0d4a78eb
BS
1693 }
1694 else if (code == 'w')
1695 {
b570063a
JZ
1696 if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
1697 fprintf (file, "%s.w", reg_names[REGNO (x)]);
1698 else
1699 output_operand_lossage ("invalid operand for code '%c'", code);
0d4a78eb
BS
1700 }
1701 else if (code == 'x')
1702 {
b570063a
JZ
1703 if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
1704 fprintf (file, "%s.x", reg_names[REGNO (x)]);
1705 else
1706 output_operand_lossage ("invalid operand for code '%c'", code);
0d4a78eb 1707 }
26c5953d
BS
1708 else if (code == 'v')
1709 {
1710 if (REGNO (x) == REG_A0)
1711 fprintf (file, "AV0");
1712 else if (REGNO (x) == REG_A1)
1713 fprintf (file, "AV1");
1714 else
1715 output_operand_lossage ("invalid operand for code '%c'", code);
1716 }
0d4a78eb
BS
1717 else if (code == 'D')
1718 {
b570063a
JZ
1719 if (D_REGNO_P (REGNO (x)))
1720 fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
1721 else
1722 output_operand_lossage ("invalid operand for code '%c'", code);
0d4a78eb
BS
1723 }
1724 else if (code == 'H')
1725 {
b570063a
JZ
1726 if ((mode == DImode || mode == DFmode) && REG_P (x))
1727 fprintf (file, "%s", reg_names[REGNO (x) + 1]);
1728 else
1729 output_operand_lossage ("invalid operand for code '%c'", code);
0d4a78eb
BS
1730 }
1731 else if (code == 'T')
1732 {
b570063a
JZ
1733 if (D_REGNO_P (REGNO (x)))
1734 fprintf (file, "%s", byte_reg_names[REGNO (x)]);
1735 else
1736 output_operand_lossage ("invalid operand for code '%c'", code);
0d4a78eb
BS
1737 }
1738 else
1739 fprintf (file, "%s", reg_names[REGNO (x)]);
1740 break;
1741
1742 case MEM:
1743 fputc ('[', file);
1744 x = XEXP (x,0);
1745 print_address_operand (file, x);
1746 fputc (']', file);
1747 break;
1748
1749 case CONST_INT:
75d8b2d0
BS
1750 if (code == 'M')
1751 {
1752 switch (INTVAL (x))
1753 {
1754 case MACFLAG_NONE:
1755 break;
1756 case MACFLAG_FU:
1757 fputs ("(FU)", file);
1758 break;
1759 case MACFLAG_T:
1760 fputs ("(T)", file);
1761 break;
1762 case MACFLAG_TFU:
1763 fputs ("(TFU)", file);
1764 break;
1765 case MACFLAG_W32:
1766 fputs ("(W32)", file);
1767 break;
1768 case MACFLAG_IS:
1769 fputs ("(IS)", file);
1770 break;
1771 case MACFLAG_IU:
1772 fputs ("(IU)", file);
1773 break;
1774 case MACFLAG_IH:
1775 fputs ("(IH)", file);
1776 break;
1777 case MACFLAG_M:
1778 fputs ("(M)", file);
1779 break;
3efd5670
BS
1780 case MACFLAG_IS_M:
1781 fputs ("(IS,M)", file);
1782 break;
75d8b2d0
BS
1783 case MACFLAG_ISS2:
1784 fputs ("(ISS2)", file);
1785 break;
1786 case MACFLAG_S2RND:
1787 fputs ("(S2RND)", file);
1788 break;
1789 default:
1790 gcc_unreachable ();
1791 }
1792 break;
1793 }
1794 else if (code == 'b')
1795 {
1796 if (INTVAL (x) == 0)
1797 fputs ("+=", file);
1798 else if (INTVAL (x) == 1)
1799 fputs ("-=", file);
1800 else
1801 gcc_unreachable ();
1802 break;
1803 }
0d4a78eb
BS
1804 /* Moves to half registers with d or h modifiers always use unsigned
1805 constants. */
75d8b2d0 1806 else if (code == 'd')
0d4a78eb
BS
1807 x = GEN_INT ((INTVAL (x) >> 16) & 0xffff);
1808 else if (code == 'h')
1809 x = GEN_INT (INTVAL (x) & 0xffff);
58f76679
BS
1810 else if (code == 'N')
1811 x = GEN_INT (-INTVAL (x));
0d4a78eb
BS
1812 else if (code == 'X')
1813 x = GEN_INT (exact_log2 (0xffffffff & INTVAL (x)));
1814 else if (code == 'Y')
1815 x = GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x)));
1816 else if (code == 'Z')
1817 /* Used for LINK insns. */
1818 x = GEN_INT (-8 - INTVAL (x));
1819
1820 /* fall through */
1821
1822 case SYMBOL_REF:
1823 output_addr_const (file, x);
0d4a78eb
BS
1824 break;
1825
1826 case CONST_DOUBLE:
1827 output_operand_lossage ("invalid const_double operand");
1828 break;
1829
1830 case UNSPEC:
3b9dd769 1831 switch (XINT (x, 1))
0d4a78eb 1832 {
3b9dd769 1833 case UNSPEC_MOVE_PIC:
0d4a78eb
BS
1834 output_addr_const (file, XVECEXP (x, 0, 0));
1835 fprintf (file, "@GOT");
3b9dd769
NS
1836 break;
1837
6614f9f5
BS
1838 case UNSPEC_MOVE_FDPIC:
1839 output_addr_const (file, XVECEXP (x, 0, 0));
1840 fprintf (file, "@GOT17M4");
1841 break;
1842
1843 case UNSPEC_FUNCDESC_GOT17M4:
1844 output_addr_const (file, XVECEXP (x, 0, 0));
1845 fprintf (file, "@FUNCDESC_GOT17M4");
1846 break;
1847
3b9dd769
NS
1848 case UNSPEC_LIBRARY_OFFSET:
1849 fprintf (file, "_current_shared_library_p5_offset_");
1850 break;
1851
1852 default:
1853 gcc_unreachable ();
0d4a78eb 1854 }
0d4a78eb
BS
1855 break;
1856
1857 default:
1858 output_addr_const (file, x);
1859 }
1860 }
1861}
1862\f
1863/* Argument support functions. */
1864
1865/* Initialize a variable CUM of type CUMULATIVE_ARGS
1866 for a call to a function whose data type is FNTYPE.
1867 For a library call, FNTYPE is 0.
1868 VDSP C Compiler manual, our ABI says that
1869 first 3 words of arguments will use R0, R1 and R2.
1870*/
1871
1872void
6d459e2b 1873init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
0d4a78eb
BS
1874 rtx libname ATTRIBUTE_UNUSED)
1875{
1876 static CUMULATIVE_ARGS zero_cum;
1877
1878 *cum = zero_cum;
1879
1880 /* Set up the number of registers to use for passing arguments. */
1881
1882 cum->nregs = max_arg_registers;
1883 cum->arg_regs = arg_regs;
1884
6d459e2b
BS
1885 cum->call_cookie = CALL_NORMAL;
1886 /* Check for a longcall attribute. */
1887 if (fntype && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
1888 cum->call_cookie |= CALL_SHORT;
1889 else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
1890 cum->call_cookie |= CALL_LONG;
1891
0d4a78eb
BS
1892 return;
1893}
1894
1895/* Update the data in CUM to advance over an argument
1896 of mode MODE and data type TYPE.
1897 (TYPE is null for libcalls where that information may not be available.) */
1898
74f41f02
NF
1899static void
1900bfin_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1901 const_tree type, bool named ATTRIBUTE_UNUSED)
0d4a78eb
BS
1902{
1903 int count, bytes, words;
1904
1905 bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1906 words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1907
1908 cum->words += words;
1909 cum->nregs -= words;
1910
1911 if (cum->nregs <= 0)
1912 {
1913 cum->nregs = 0;
1914 cum->arg_regs = NULL;
1915 }
1916 else
1917 {
1918 for (count = 1; count <= words; count++)
1919 cum->arg_regs++;
1920 }
1921
1922 return;
1923}
1924
1925/* Define where to put the arguments to a function.
1926 Value is zero to push the argument on the stack,
1927 or a hard register in which to store the argument.
1928
1929 MODE is the argument's machine mode.
1930 TYPE is the data type of the argument (as a tree).
1931 This is null for libcalls where that information may
1932 not be available.
1933 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1934 the preceding args and about the function being called.
1935 NAMED is nonzero if this argument is a named parameter
1936 (otherwise it is an extra parameter matching an ellipsis). */
1937
74f41f02
NF
1938static rtx
1939bfin_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1940 const_tree type, bool named ATTRIBUTE_UNUSED)
0d4a78eb
BS
1941{
1942 int bytes
1943 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1944
6d459e2b
BS
1945 if (mode == VOIDmode)
1946 /* Compute operand 2 of the call insn. */
1947 return GEN_INT (cum->call_cookie);
1948
0d4a78eb
BS
1949 if (bytes == -1)
1950 return NULL_RTX;
1951
1952 if (cum->nregs)
1953 return gen_rtx_REG (mode, *(cum->arg_regs));
1954
1955 return NULL_RTX;
1956}
1957
1958/* For an arg passed partly in registers and partly in memory,
1959 this is the number of bytes passed in registers.
1960 For args passed entirely in registers or entirely in memory, zero.
1961
1962 Refer VDSP C Compiler manual, our ABI.
ea2c620c 1963 First 3 words are in registers. So, if an argument is larger
0d4a78eb
BS
1964 than the registers available, it will span the register and
1965 stack. */
1966
1967static int
1968bfin_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1969 tree type ATTRIBUTE_UNUSED,
1970 bool named ATTRIBUTE_UNUSED)
1971{
1972 int bytes
1973 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1974 int bytes_left = cum->nregs * UNITS_PER_WORD;
1975
1976 if (bytes == -1)
1977 return 0;
1978
1979 if (bytes_left == 0)
1980 return 0;
1981 if (bytes > bytes_left)
1982 return bytes_left;
1983 return 0;
1984}
1985
1986/* Variable sized types are passed by reference. */
1987
1988static bool
1989bfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
1990 enum machine_mode mode ATTRIBUTE_UNUSED,
586de218 1991 const_tree type, bool named ATTRIBUTE_UNUSED)
0d4a78eb
BS
1992{
1993 return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
1994}
1995
1996/* Decide whether a type should be returned in memory (true)
1997 or in a register (false). This is called by the macro
81464b2c 1998 TARGET_RETURN_IN_MEMORY. */
0d4a78eb 1999
7ba20e60 2000static bool
81464b2c 2001bfin_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
0d4a78eb 2002{
07da68fd
JZ
2003 int size = int_size_in_bytes (type);
2004 return size > 2 * UNITS_PER_WORD || size == -1;
0d4a78eb
BS
2005}
2006
2007/* Register in which address to store a structure value
2008 is passed to a function. */
2009static rtx
2010bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
2011 int incoming ATTRIBUTE_UNUSED)
2012{
2013 return gen_rtx_REG (Pmode, REG_P0);
2014}
2015
2016/* Return true when register may be used to pass function parameters. */
2017
2018bool
2019function_arg_regno_p (int n)
2020{
2021 int i;
2022 for (i = 0; arg_regs[i] != -1; i++)
2023 if (n == arg_regs[i])
2024 return true;
2025 return false;
2026}
2027
2028/* Returns 1 if OP contains a symbol reference */
2029
2030int
2031symbolic_reference_mentioned_p (rtx op)
2032{
2033 register const char *fmt;
2034 register int i;
2035
2036 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
2037 return 1;
2038
2039 fmt = GET_RTX_FORMAT (GET_CODE (op));
2040 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
2041 {
2042 if (fmt[i] == 'E')
2043 {
2044 register int j;
2045
2046 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
2047 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
2048 return 1;
2049 }
2050
2051 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
2052 return 1;
2053 }
2054
2055 return 0;
2056}
2057
2058/* Decide whether we can make a sibling call to a function. DECL is the
2059 declaration of the function being targeted by the call and EXP is the
2060 CALL_EXPR representing the call. */
2061
2062static bool
2063bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
2064 tree exp ATTRIBUTE_UNUSED)
2065{
7e8b322a 2066 struct cgraph_local_info *this_func, *called_func;
e989202f 2067 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
bcbb974d
BS
2068 if (fkind != SUBROUTINE)
2069 return false;
2070 if (!TARGET_ID_SHARED_LIBRARY || TARGET_SEP_DATA)
2071 return true;
2072
2073 /* When compiling for ID shared libraries, can't sibcall a local function
2074 from a non-local function, because the local function thinks it does
2075 not need to reload P5 in the prologue, but the sibcall wil pop P5 in the
2076 sibcall epilogue, and we end up with the wrong value in P5. */
2077
d8612738
BS
2078 if (!decl)
2079 /* Not enough information. */
2080 return false;
bcbb974d 2081
7e8b322a
JH
2082 this_func = cgraph_local_info (current_function_decl);
2083 called_func = cgraph_local_info (decl);
2084 return !called_func->local || this_func->local;
0d4a78eb
BS
2085}
2086\f
92910d77
RH
2087/* Write a template for a trampoline to F. */
2088
2089static void
2090bfin_asm_trampoline_template (FILE *f)
2091{
2092 if (TARGET_FDPIC)
2093 {
2094 fprintf (f, "\t.dd\t0x00000000\n"); /* 0 */
2095 fprintf (f, "\t.dd\t0x00000000\n"); /* 0 */
2096 fprintf (f, "\t.dd\t0x0000e109\n"); /* p1.l = fn low */
2097 fprintf (f, "\t.dd\t0x0000e149\n"); /* p1.h = fn high */
2098 fprintf (f, "\t.dd\t0x0000e10a\n"); /* p2.l = sc low */
2099 fprintf (f, "\t.dd\t0x0000e14a\n"); /* p2.h = sc high */
2100 fprintf (f, "\t.dw\t0xac4b\n"); /* p3 = [p1 + 4] */
2101 fprintf (f, "\t.dw\t0x9149\n"); /* p1 = [p1] */
2102 fprintf (f, "\t.dw\t0x0051\n"); /* jump (p1)*/
2103 }
2104 else
2105 {
2106 fprintf (f, "\t.dd\t0x0000e109\n"); /* p1.l = fn low */
2107 fprintf (f, "\t.dd\t0x0000e149\n"); /* p1.h = fn high */
2108 fprintf (f, "\t.dd\t0x0000e10a\n"); /* p2.l = sc low */
2109 fprintf (f, "\t.dd\t0x0000e14a\n"); /* p2.h = sc high */
2110 fprintf (f, "\t.dw\t0x0051\n"); /* jump (p1)*/
2111 }
2112}
2113
0d4a78eb 2114/* Emit RTL insns to initialize the variable parts of a trampoline at
92910d77
RH
2115 M_TRAMP. FNDECL is the target function. CHAIN_VALUE is an RTX for
2116 the static chain value for the function. */
0d4a78eb 2117
92910d77
RH
2118static void
2119bfin_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
0d4a78eb 2120{
92910d77
RH
2121 rtx t1 = copy_to_reg (XEXP (DECL_RTL (fndecl), 0));
2122 rtx t2 = copy_to_reg (chain_value);
2123 rtx mem;
6614f9f5
BS
2124 int i = 0;
2125
92910d77
RH
2126 emit_block_move (m_tramp, assemble_trampoline_template (),
2127 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
2128
6614f9f5
BS
2129 if (TARGET_FDPIC)
2130 {
92910d77
RH
2131 rtx a = force_reg (Pmode, plus_constant (XEXP (m_tramp, 0), 8));
2132 mem = adjust_address (m_tramp, Pmode, 0);
2133 emit_move_insn (mem, a);
6614f9f5
BS
2134 i = 8;
2135 }
0d4a78eb 2136
92910d77
RH
2137 mem = adjust_address (m_tramp, HImode, i + 2);
2138 emit_move_insn (mem, gen_lowpart (HImode, t1));
0d4a78eb 2139 emit_insn (gen_ashrsi3 (t1, t1, GEN_INT (16)));
92910d77
RH
2140 mem = adjust_address (m_tramp, HImode, i + 6);
2141 emit_move_insn (mem, gen_lowpart (HImode, t1));
0d4a78eb 2142
92910d77
RH
2143 mem = adjust_address (m_tramp, HImode, i + 10);
2144 emit_move_insn (mem, gen_lowpart (HImode, t2));
0d4a78eb 2145 emit_insn (gen_ashrsi3 (t2, t2, GEN_INT (16)));
92910d77
RH
2146 mem = adjust_address (m_tramp, HImode, i + 14);
2147 emit_move_insn (mem, gen_lowpart (HImode, t2));
0d4a78eb
BS
2148}
2149
0d4a78eb
BS
2150/* Emit insns to move operands[1] into operands[0]. */
2151
2152void
2153emit_pic_move (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
2154{
2155 rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
2156
6614f9f5 2157 gcc_assert (!TARGET_FDPIC || !(reload_in_progress || reload_completed));
0d4a78eb
BS
2158 if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
2159 operands[1] = force_reg (SImode, operands[1]);
2160 else
09350e36 2161 operands[1] = legitimize_pic_address (operands[1], temp,
6614f9f5
BS
2162 TARGET_FDPIC ? OUR_FDPIC_REG
2163 : pic_offset_table_rtx);
0d4a78eb
BS
2164}
2165
d6f6753e
BS
2166/* Expand a move operation in mode MODE. The operands are in OPERANDS.
2167 Returns true if no further code must be generated, false if the caller
2168 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
0d4a78eb 2169
d6f6753e 2170bool
0d4a78eb
BS
2171expand_move (rtx *operands, enum machine_mode mode)
2172{
6614f9f5
BS
2173 rtx op = operands[1];
2174 if ((TARGET_ID_SHARED_LIBRARY || TARGET_FDPIC)
2175 && SYMBOLIC_CONST (op))
0d4a78eb 2176 emit_pic_move (operands, mode);
d6f6753e
BS
2177 else if (mode == SImode && GET_CODE (op) == CONST
2178 && GET_CODE (XEXP (op, 0)) == PLUS
2179 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
2180 && !bfin_legitimate_constant_p (op))
2181 {
2182 rtx dest = operands[0];
2183 rtx op0, op1;
2184 gcc_assert (!reload_in_progress && !reload_completed);
2185 op = XEXP (op, 0);
2186 op0 = force_reg (mode, XEXP (op, 0));
2187 op1 = XEXP (op, 1);
2188 if (!insn_data[CODE_FOR_addsi3].operand[2].predicate (op1, mode))
2189 op1 = force_reg (mode, op1);
2190 if (GET_CODE (dest) == MEM)
2191 dest = gen_reg_rtx (mode);
2192 emit_insn (gen_addsi3 (dest, op0, op1));
2193 if (dest == operands[0])
2194 return true;
2195 operands[1] = dest;
2196 }
0d4a78eb
BS
2197 /* Don't generate memory->memory or constant->memory moves, go through a
2198 register */
2199 else if ((reload_in_progress | reload_completed) == 0
2200 && GET_CODE (operands[0]) == MEM
2201 && GET_CODE (operands[1]) != REG)
2202 operands[1] = force_reg (mode, operands[1]);
d6f6753e 2203 return false;
0d4a78eb
BS
2204}
2205\f
2206/* Split one or more DImode RTL references into pairs of SImode
2207 references. The RTL can be REG, offsettable MEM, integer constant, or
2208 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
2209 split and "num" is its length. lo_half and hi_half are output arrays
2210 that parallel "operands". */
2211
2212void
2213split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
2214{
2215 while (num--)
2216 {
2217 rtx op = operands[num];
2218
2219 /* simplify_subreg refuse to split volatile memory addresses,
2220 but we still have to handle it. */
2221 if (GET_CODE (op) == MEM)
2222 {
2223 lo_half[num] = adjust_address (op, SImode, 0);
2224 hi_half[num] = adjust_address (op, SImode, 4);
2225 }
2226 else
2227 {
2228 lo_half[num] = simplify_gen_subreg (SImode, op,
2229 GET_MODE (op) == VOIDmode
2230 ? DImode : GET_MODE (op), 0);
2231 hi_half[num] = simplify_gen_subreg (SImode, op,
2232 GET_MODE (op) == VOIDmode
2233 ? DImode : GET_MODE (op), 4);
2234 }
2235 }
2236}
2237\f
6d459e2b
BS
2238bool
2239bfin_longcall_p (rtx op, int call_cookie)
2240{
2241 gcc_assert (GET_CODE (op) == SYMBOL_REF);
49caeea1
BS
2242 if (SYMBOL_REF_WEAK (op))
2243 return 1;
6d459e2b
BS
2244 if (call_cookie & CALL_SHORT)
2245 return 0;
2246 if (call_cookie & CALL_LONG)
2247 return 1;
2248 if (TARGET_LONG_CALLS)
2249 return 1;
2250 return 0;
2251}
2252
0d4a78eb 2253/* Expand a call instruction. FNADDR is the call target, RETVAL the return value.
6d459e2b 2254 COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
0d4a78eb
BS
2255 SIBCALL is nonzero if this is a sibling call. */
2256
2257void
6d459e2b 2258bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall)
0d4a78eb
BS
2259{
2260 rtx use = NULL, call;
6d459e2b 2261 rtx callee = XEXP (fnaddr, 0);
9840d30a 2262 int nelts = 3;
6614f9f5
BS
2263 rtx pat;
2264 rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REGNO);
9840d30a 2265 rtx retsreg = gen_rtx_REG (Pmode, REG_RETS);
6614f9f5 2266 int n;
6d459e2b
BS
2267
2268 /* In an untyped call, we can get NULL for operand 2. */
2269 if (cookie == NULL_RTX)
2270 cookie = const0_rtx;
0d4a78eb
BS
2271
2272 /* Static functions and indirect calls don't need the pic register. */
6614f9f5 2273 if (!TARGET_FDPIC && flag_pic
6d459e2b
BS
2274 && GET_CODE (callee) == SYMBOL_REF
2275 && !SYMBOL_REF_LOCAL_P (callee))
0d4a78eb
BS
2276 use_reg (&use, pic_offset_table_rtx);
2277
6614f9f5
BS
2278 if (TARGET_FDPIC)
2279 {
db689ed6 2280 int caller_in_sram, callee_in_sram;
4af797b5 2281
db689ed6
BS
2282 /* 0 is not in sram, 1 is in L1 sram, 2 is in L2 sram. */
2283 caller_in_sram = callee_in_sram = 0;
4af797b5
JZ
2284
2285 if (lookup_attribute ("l1_text",
2286 DECL_ATTRIBUTES (cfun->decl)) != NULL_TREE)
db689ed6
BS
2287 caller_in_sram = 1;
2288 else if (lookup_attribute ("l2",
2289 DECL_ATTRIBUTES (cfun->decl)) != NULL_TREE)
2290 caller_in_sram = 2;
4af797b5
JZ
2291
2292 if (GET_CODE (callee) == SYMBOL_REF
db689ed6
BS
2293 && SYMBOL_REF_DECL (callee) && DECL_P (SYMBOL_REF_DECL (callee)))
2294 {
2295 if (lookup_attribute
2296 ("l1_text",
2297 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee))) != NULL_TREE)
2298 callee_in_sram = 1;
2299 else if (lookup_attribute
2300 ("l2",
2301 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee))) != NULL_TREE)
2302 callee_in_sram = 2;
2303 }
4af797b5 2304
6614f9f5 2305 if (GET_CODE (callee) != SYMBOL_REF
e874e49f
JZ
2306 || bfin_longcall_p (callee, INTVAL (cookie))
2307 || (GET_CODE (callee) == SYMBOL_REF
2308 && !SYMBOL_REF_LOCAL_P (callee)
4af797b5 2309 && TARGET_INLINE_PLT)
db689ed6
BS
2310 || caller_in_sram != callee_in_sram
2311 || (caller_in_sram && callee_in_sram
4af797b5
JZ
2312 && (GET_CODE (callee) != SYMBOL_REF
2313 || !SYMBOL_REF_LOCAL_P (callee))))
6614f9f5
BS
2314 {
2315 rtx addr = callee;
2316 if (! address_operand (addr, Pmode))
2317 addr = force_reg (Pmode, addr);
2318
2319 fnaddr = gen_reg_rtx (SImode);
2320 emit_insn (gen_load_funcdescsi (fnaddr, addr));
2321 fnaddr = gen_rtx_MEM (Pmode, fnaddr);
2322
2323 picreg = gen_reg_rtx (SImode);
2324 emit_insn (gen_load_funcdescsi (picreg,
2325 plus_constant (addr, 4)));
2326 }
2327
2328 nelts++;
2329 }
2330 else if ((!register_no_elim_operand (callee, Pmode)
2331 && GET_CODE (callee) != SYMBOL_REF)
2332 || (GET_CODE (callee) == SYMBOL_REF
93147119 2333 && ((TARGET_ID_SHARED_LIBRARY && !TARGET_LEAF_ID_SHARED_LIBRARY)
6614f9f5 2334 || bfin_longcall_p (callee, INTVAL (cookie)))))
0d4a78eb 2335 {
6d459e2b
BS
2336 callee = copy_to_mode_reg (Pmode, callee);
2337 fnaddr = gen_rtx_MEM (Pmode, callee);
0d4a78eb
BS
2338 }
2339 call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
2340
2341 if (retval)
2342 call = gen_rtx_SET (VOIDmode, retval, call);
6d459e2b 2343
6614f9f5
BS
2344 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nelts));
2345 n = 0;
2346 XVECEXP (pat, 0, n++) = call;
2347 if (TARGET_FDPIC)
2348 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, picreg);
2349 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, cookie);
0d4a78eb 2350 if (sibcall)
6614f9f5 2351 XVECEXP (pat, 0, n++) = gen_rtx_RETURN (VOIDmode);
9840d30a
BS
2352 else
2353 XVECEXP (pat, 0, n++) = gen_rtx_CLOBBER (VOIDmode, retsreg);
6d459e2b 2354 call = emit_call_insn (pat);
0d4a78eb
BS
2355 if (use)
2356 CALL_INSN_FUNCTION_USAGE (call) = use;
2357}
2358\f
2359/* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
2360
2361int
2362hard_regno_mode_ok (int regno, enum machine_mode mode)
2363{
2364 /* Allow only dregs to store value of mode HI or QI */
0a2aaacc 2365 enum reg_class rclass = REGNO_REG_CLASS (regno);
0d4a78eb
BS
2366
2367 if (mode == CCmode)
2368 return 0;
2369
2370 if (mode == V2HImode)
2371 return D_REGNO_P (regno);
0a2aaacc 2372 if (rclass == CCREGS)
0d4a78eb 2373 return mode == BImode;
75d8b2d0 2374 if (mode == PDImode || mode == V2PDImode)
0d4a78eb 2375 return regno == REG_A0 || regno == REG_A1;
84e32cbb 2376
942fd98f 2377 /* Allow all normal 32-bit regs, except REG_M3, in case regclass ever comes
84e32cbb
BS
2378 up with a bad register class (such as ALL_REGS) for DImode. */
2379 if (mode == DImode)
2380 return regno < REG_M3;
2381
0d4a78eb
BS
2382 if (mode == SImode
2383 && TEST_HARD_REG_BIT (reg_class_contents[PROLOGUE_REGS], regno))
2384 return 1;
84e32cbb 2385
0d4a78eb
BS
2386 return TEST_HARD_REG_BIT (reg_class_contents[MOST_REGS], regno);
2387}
2388
2389/* Implements target hook vector_mode_supported_p. */
2390
2391static bool
2392bfin_vector_mode_supported_p (enum machine_mode mode)
2393{
2394 return mode == V2HImode;
2395}
2396
2397/* Return the cost of moving data from a register in class CLASS1 to
2398 one in class CLASS2. A cost of 2 is the default. */
2399
2400int
84e32cbb 2401bfin_register_move_cost (enum machine_mode mode,
0d4a78eb
BS
2402 enum reg_class class1, enum reg_class class2)
2403{
4729dc92 2404 /* These need secondary reloads, so they're more expensive. */
c5d96723
BS
2405 if ((class1 == CCREGS && !reg_class_subset_p (class2, DREGS))
2406 || (class2 == CCREGS && !reg_class_subset_p (class1, DREGS)))
4729dc92
BS
2407 return 4;
2408
0d4a78eb
BS
2409 /* If optimizing for size, always prefer reg-reg over reg-memory moves. */
2410 if (optimize_size)
2411 return 2;
2412
84e32cbb
BS
2413 if (GET_MODE_CLASS (mode) == MODE_INT)
2414 {
2415 /* Discourage trying to use the accumulators. */
2416 if (TEST_HARD_REG_BIT (reg_class_contents[class1], REG_A0)
2417 || TEST_HARD_REG_BIT (reg_class_contents[class1], REG_A1)
2418 || TEST_HARD_REG_BIT (reg_class_contents[class2], REG_A0)
2419 || TEST_HARD_REG_BIT (reg_class_contents[class2], REG_A1))
2420 return 20;
2421 }
0d4a78eb
BS
2422 return 2;
2423}
2424
2425/* Return the cost of moving data of mode M between a
2426 register and memory. A value of 2 is the default; this cost is
2427 relative to those in `REGISTER_MOVE_COST'.
2428
2429 ??? In theory L1 memory has single-cycle latency. We should add a switch
2430 that tells the compiler whether we expect to use only L1 memory for the
2431 program; it'll make the costs more accurate. */
2432
2433int
2434bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
0a2aaacc 2435 enum reg_class rclass,
0d4a78eb
BS
2436 int in ATTRIBUTE_UNUSED)
2437{
2438 /* Make memory accesses slightly more expensive than any register-register
2439 move. Also, penalize non-DP registers, since they need secondary
2440 reloads to load and store. */
0a2aaacc 2441 if (! reg_class_subset_p (rclass, DPREGS))
0d4a78eb
BS
2442 return 10;
2443
2444 return 8;
2445}
2446
2447/* Inform reload about cases where moving X with a mode MODE to a register in
0a2aaacc 2448 RCLASS requires an extra scratch register. Return the class needed for the
0d4a78eb
BS
2449 scratch register. */
2450
a87cf97e
JR
2451static reg_class_t
2452bfin_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
6ed44ca1 2453 enum machine_mode mode, secondary_reload_info *sri)
0d4a78eb
BS
2454{
2455 /* If we have HImode or QImode, we can only use DREGS as secondary registers;
2456 in most other cases we can also use PREGS. */
2457 enum reg_class default_class = GET_MODE_SIZE (mode) >= 4 ? DPREGS : DREGS;
2458 enum reg_class x_class = NO_REGS;
2459 enum rtx_code code = GET_CODE (x);
a87cf97e 2460 enum reg_class rclass = (enum reg_class) rclass_i;
0d4a78eb
BS
2461
2462 if (code == SUBREG)
2463 x = SUBREG_REG (x), code = GET_CODE (x);
2464 if (REG_P (x))
2465 {
2466 int regno = REGNO (x);
2467 if (regno >= FIRST_PSEUDO_REGISTER)
2468 regno = reg_renumber[regno];
2469
2470 if (regno == -1)
2471 code = MEM;
2472 else
2473 x_class = REGNO_REG_CLASS (regno);
2474 }
2475
2476 /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
2477 This happens as a side effect of register elimination, and we need
2478 a scratch register to do it. */
2479 if (fp_plus_const_operand (x, mode))
2480 {
2481 rtx op2 = XEXP (x, 1);
9fdd7520 2482 int large_constant_p = ! satisfies_constraint_Ks7 (op2);
0d4a78eb 2483
0a2aaacc 2484 if (rclass == PREGS || rclass == PREGS_CLOBBERED)
0d4a78eb
BS
2485 return NO_REGS;
2486 /* If destination is a DREG, we can do this without a scratch register
2487 if the constant is valid for an add instruction. */
0a2aaacc 2488 if ((rclass == DREGS || rclass == DPREGS)
e97f2058
BS
2489 && ! large_constant_p)
2490 return NO_REGS;
0d4a78eb
BS
2491 /* Reloading to anything other than a DREG? Use a PREG scratch
2492 register. */
e97f2058
BS
2493 sri->icode = CODE_FOR_reload_insi;
2494 return NO_REGS;
0d4a78eb
BS
2495 }
2496
2497 /* Data can usually be moved freely between registers of most classes.
2498 AREGS are an exception; they can only move to or from another register
2499 in AREGS or one in DREGS. They can also be assigned the constant 0. */
3efd5670 2500 if (x_class == AREGS || x_class == EVEN_AREGS || x_class == ODD_AREGS)
0a2aaacc
KG
2501 return (rclass == DREGS || rclass == AREGS || rclass == EVEN_AREGS
2502 || rclass == ODD_AREGS
3efd5670 2503 ? NO_REGS : DREGS);
0d4a78eb 2504
0a2aaacc 2505 if (rclass == AREGS || rclass == EVEN_AREGS || rclass == ODD_AREGS)
0d4a78eb 2506 {
6ed44ca1
BS
2507 if (code == MEM)
2508 {
2509 sri->icode = in_p ? CODE_FOR_reload_inpdi : CODE_FOR_reload_outpdi;
2510 return NO_REGS;
2511 }
2512
0d4a78eb 2513 if (x != const0_rtx && x_class != DREGS)
6ed44ca1
BS
2514 {
2515 return DREGS;
2516 }
0d4a78eb
BS
2517 else
2518 return NO_REGS;
2519 }
2520
2521 /* CCREGS can only be moved from/to DREGS. */
0a2aaacc 2522 if (rclass == CCREGS && x_class != DREGS)
0d4a78eb 2523 return DREGS;
0a2aaacc 2524 if (x_class == CCREGS && rclass != DREGS)
0d4a78eb 2525 return DREGS;
4729dc92 2526
0d4a78eb
BS
2527 /* All registers other than AREGS can load arbitrary constants. The only
2528 case that remains is MEM. */
2529 if (code == MEM)
0a2aaacc 2530 if (! reg_class_subset_p (rclass, default_class))
0d4a78eb 2531 return default_class;
6ed44ca1 2532
0d4a78eb
BS
2533 return NO_REGS;
2534}
0b182178
AS
2535
2536/* Implement TARGET_CLASS_LIKELY_SPILLED_P. */
2537
2538static bool
2539bfin_class_likely_spilled_p (reg_class_t rclass)
2540{
2541 switch (rclass)
2542 {
2543 case PREGS_CLOBBERED:
2544 case PROLOGUE_REGS:
2545 case P0REGS:
2546 case D0REGS:
2547 case D1REGS:
2548 case D2REGS:
2549 case CCREGS:
2550 return true;
2551
2552 default:
2553 break;
2554 }
2555
2556 return false;
2557}
0d4a78eb 2558\f
f02a5d0e
BS
2559/* Implement TARGET_HANDLE_OPTION. */
2560
2561static bool
96e45421
JM
2562bfin_handle_option (struct gcc_options *opts, struct gcc_options *opts_set,
2563 const struct cl_decoded_option *decoded,
2564 location_t loc ATTRIBUTE_UNUSED)
f02a5d0e 2565{
96e45421
JM
2566 size_t code = decoded->opt_index;
2567 const char *arg = decoded->arg;
2568 int value = decoded->value;
2569
2570 gcc_assert (opts == &global_options);
2571 gcc_assert (opts_set == &global_options_set);
2572
f02a5d0e
BS
2573 switch (code)
2574 {
2575 case OPT_mshared_library_id_:
2576 if (value > MAX_LIBRARY_ID)
2577 error ("-mshared-library-id=%s is not between 0 and %d",
2578 arg, MAX_LIBRARY_ID);
c8de0f3b 2579 bfin_lib_id_given = 1;
f02a5d0e
BS
2580 return true;
2581
9d3f9aa3 2582 case OPT_mcpu_:
ea2382be
JZ
2583 {
2584 const char *p, *q;
2585 int i;
2586
2587 i = 0;
2588 while ((p = bfin_cpus[i].name) != NULL)
2589 {
2590 if (strncmp (arg, p, strlen (p)) == 0)
2591 break;
2592 i++;
2593 }
2594
2595 if (p == NULL)
2596 {
2597 error ("-mcpu=%s is not valid", arg);
2598 return false;
2599 }
2600
2601 bfin_cpu_type = bfin_cpus[i].type;
2602
2603 q = arg + strlen (p);
2604
2605 if (*q == '\0')
2606 {
2607 bfin_si_revision = bfin_cpus[i].si_revision;
2608 bfin_workarounds |= bfin_cpus[i].workarounds;
2609 }
2610 else if (strcmp (q, "-none") == 0)
2611 bfin_si_revision = -1;
2612 else if (strcmp (q, "-any") == 0)
2613 {
2614 bfin_si_revision = 0xffff;
2615 while (bfin_cpus[i].type == bfin_cpu_type)
2616 {
2617 bfin_workarounds |= bfin_cpus[i].workarounds;
2618 i++;
2619 }
2620 }
2621 else
2622 {
2623 unsigned int si_major, si_minor;
2624 int rev_len, n;
2625
2626 rev_len = strlen (q);
2627
2628 if (sscanf (q, "-%u.%u%n", &si_major, &si_minor, &n) != 2
2629 || n != rev_len
2630 || si_major > 0xff || si_minor > 0xff)
2631 {
2632 invalid_silicon_revision:
2633 error ("-mcpu=%s has invalid silicon revision", arg);
2634 return false;
2635 }
2636
2637 bfin_si_revision = (si_major << 8) | si_minor;
2638
2639 while (bfin_cpus[i].type == bfin_cpu_type
2640 && bfin_cpus[i].si_revision != bfin_si_revision)
2641 i++;
2642
2643 if (bfin_cpus[i].type != bfin_cpu_type)
2644 goto invalid_silicon_revision;
2645
2646 bfin_workarounds |= bfin_cpus[i].workarounds;
2647 }
2648
ea2382be
JZ
2649 return true;
2650 }
9d3f9aa3 2651
f02a5d0e
BS
2652 default:
2653 return true;
2654 }
2655}
2656
b03149e1
JZ
2657static struct machine_function *
2658bfin_init_machine_status (void)
2659{
a9429e29 2660 return ggc_alloc_cleared_machine_function ();
b03149e1
JZ
2661}
2662
c5387660 2663/* Implement the TARGET_OPTION_OVERRIDE hook. */
0d4a78eb 2664
c5387660
JM
2665static void
2666bfin_option_override (void)
0d4a78eb 2667{
16869606
BS
2668 /* If processor type is not specified, enable all workarounds. */
2669 if (bfin_cpu_type == BFIN_CPU_UNKNOWN)
2670 {
2671 int i;
2672
2673 for (i = 0; bfin_cpus[i].name != NULL; i++)
2674 bfin_workarounds |= bfin_cpus[i].workarounds;
2675
2676 bfin_si_revision = 0xffff;
2677 }
2678
ea2382be
JZ
2679 if (bfin_csync_anomaly == 1)
2680 bfin_workarounds |= WA_SPECULATIVE_SYNCS;
2681 else if (bfin_csync_anomaly == 0)
2682 bfin_workarounds &= ~WA_SPECULATIVE_SYNCS;
2683
2684 if (bfin_specld_anomaly == 1)
2685 bfin_workarounds |= WA_SPECULATIVE_LOADS;
2686 else if (bfin_specld_anomaly == 0)
2687 bfin_workarounds &= ~WA_SPECULATIVE_LOADS;
2688
0d4a78eb
BS
2689 if (TARGET_OMIT_LEAF_FRAME_POINTER)
2690 flag_omit_frame_pointer = 1;
2691
2692 /* Library identification */
f02a5d0e
BS
2693 if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY)
2694 error ("-mshared-library-id= specified without -mid-shared-library");
0d4a78eb 2695
d6eb07dc 2696 if (stack_limit_rtx && TARGET_STACK_CHECK_L1)
d8a07487 2697 error ("can%'t use multiple stack checking methods together");
d6eb07dc 2698
6614f9f5 2699 if (TARGET_ID_SHARED_LIBRARY && TARGET_FDPIC)
d8a07487 2700 error ("ID shared libraries and FD-PIC mode can%'t be used together");
6614f9f5 2701
93147119
BS
2702 /* Don't allow the user to specify -mid-shared-library and -msep-data
2703 together, as it makes little sense from a user's point of view... */
2704 if (TARGET_SEP_DATA && TARGET_ID_SHARED_LIBRARY)
2705 error ("cannot specify both -msep-data and -mid-shared-library");
2706 /* ... internally, however, it's nearly the same. */
2707 if (TARGET_SEP_DATA)
2708 target_flags |= MASK_ID_SHARED_LIBRARY | MASK_LEAF_ID_SHARED_LIBRARY;
2709
fb7c3b05
BS
2710 if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0)
2711 flag_pic = 1;
2712
6614f9f5
BS
2713 /* There is no single unaligned SI op for PIC code. Sometimes we
2714 need to use ".4byte" and sometimes we need to use ".picptr".
2715 See bfin_assemble_integer for details. */
2716 if (TARGET_FDPIC)
2717 targetm.asm_out.unaligned_op.si = 0;
2718
2719 /* Silently turn off flag_pic if not doing FDPIC or ID shared libraries,
2720 since we don't support it and it'll just break. */
2721 if (flag_pic && !TARGET_FDPIC && !TARGET_ID_SHARED_LIBRARY)
2722 flag_pic = 0;
2723
16869606
BS
2724 if (TARGET_MULTICORE && bfin_cpu_type != BFIN_CPU_BF561)
2725 error ("-mmulticore can only be used with BF561");
2726
2727 if (TARGET_COREA && !TARGET_MULTICORE)
2728 error ("-mcorea should be used with -mmulticore");
2729
2730 if (TARGET_COREB && !TARGET_MULTICORE)
2731 error ("-mcoreb should be used with -mmulticore");
2732
2733 if (TARGET_COREA && TARGET_COREB)
d8a07487 2734 error ("-mcorea and -mcoreb can%'t be used together");
16869606 2735
0d4a78eb 2736 flag_schedule_insns = 0;
b03149e1 2737
bbbc206e
BS
2738 /* Passes after sched2 can break the helpful TImode annotations that
2739 haifa-sched puts on every insn. Just do scheduling in reorg. */
2740 bfin_flag_schedule_insns2 = flag_schedule_insns_after_reload;
2741 flag_schedule_insns_after_reload = 0;
2742
b03149e1 2743 init_machine_status = bfin_init_machine_status;
0d4a78eb
BS
2744}
2745
a2391c6a
JZ
2746/* Return the destination address of BRANCH.
2747 We need to use this instead of get_attr_length, because the
2748 cbranch_with_nops pattern conservatively sets its length to 6, and
2749 we still prefer to use shorter sequences. */
0d4a78eb
BS
2750
2751static int
2752branch_dest (rtx branch)
2753{
2754 rtx dest;
2755 int dest_uid;
2756 rtx pat = PATTERN (branch);
2757 if (GET_CODE (pat) == PARALLEL)
2758 pat = XVECEXP (pat, 0, 0);
2759 dest = SET_SRC (pat);
2760 if (GET_CODE (dest) == IF_THEN_ELSE)
2761 dest = XEXP (dest, 1);
2762 dest = XEXP (dest, 0);
2763 dest_uid = INSN_UID (dest);
2764 return INSN_ADDRESSES (dest_uid);
2765}
2766
2767/* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
2768 it's a branch that's predicted taken. */
2769
2770static int
2771cbranch_predicted_taken_p (rtx insn)
2772{
2773 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2774
2775 if (x)
2776 {
2777 int pred_val = INTVAL (XEXP (x, 0));
2778
2779 return pred_val >= REG_BR_PROB_BASE / 2;
2780 }
2781
2782 return 0;
2783}
2784
2785/* Templates for use by asm_conditional_branch. */
2786
2787static const char *ccbranch_templates[][3] = {
2788 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
2789 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
2790 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
2791 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
2792};
2793
2794/* Output INSN, which is a conditional branch instruction with operands
2795 OPERANDS.
2796
2797 We deal with the various forms of conditional branches that can be generated
2798 by bfin_reorg to prevent the hardware from doing speculative loads, by
2799 - emitting a sufficient number of nops, if N_NOPS is nonzero, or
2800 - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
2801 Either of these is only necessary if the branch is short, otherwise the
2802 template we use ends in an unconditional jump which flushes the pipeline
2803 anyway. */
2804
2805void
2806asm_conditional_branch (rtx insn, rtx *operands, int n_nops, int predict_taken)
2807{
2808 int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
2809 /* Note : offset for instructions like if cc jmp; jump.[sl] offset
2810 is to be taken from start of if cc rather than jump.
2811 Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
2812 */
2813 int len = (offset >= -1024 && offset <= 1022 ? 0
2814 : offset >= -4094 && offset <= 4096 ? 1
2815 : 2);
2816 int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p (insn);
2817 int idx = (bp << 1) | (GET_CODE (operands[0]) == EQ ? BRF : BRT);
2818 output_asm_insn (ccbranch_templates[idx][len], operands);
3b9dd769 2819 gcc_assert (n_nops == 0 || !bp);
0d4a78eb
BS
2820 if (len == 0)
2821 while (n_nops-- > 0)
2822 output_asm_insn ("nop;", NULL);
2823}
2824
2825/* Emit rtl for a comparison operation CMP in mode MODE. Operands have been
2826 stored in bfin_compare_op0 and bfin_compare_op1 already. */
2827
2828rtx
2829bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED)
2830{
2831 enum rtx_code code1, code2;
f90b7a5a 2832 rtx op0 = XEXP (cmp, 0), op1 = XEXP (cmp, 1);
0d4a78eb
BS
2833 rtx tem = bfin_cc_rtx;
2834 enum rtx_code code = GET_CODE (cmp);
2835
2836 /* If we have a BImode input, then we already have a compare result, and
2837 do not need to emit another comparison. */
2838 if (GET_MODE (op0) == BImode)
2839 {
3b9dd769
NS
2840 gcc_assert ((code == NE || code == EQ) && op1 == const0_rtx);
2841 tem = op0, code2 = code;
0d4a78eb
BS
2842 }
2843 else
2844 {
2845 switch (code) {
2846 /* bfin has these conditions */
2847 case EQ:
2848 case LT:
2849 case LE:
2850 case LEU:
2851 case LTU:
2852 code1 = code;
2853 code2 = NE;
2854 break;
2855 default:
2856 code1 = reverse_condition (code);
2857 code2 = EQ;
2858 break;
2859 }
f90b7a5a 2860 emit_insn (gen_rtx_SET (VOIDmode, tem,
0d4a78eb
BS
2861 gen_rtx_fmt_ee (code1, BImode, op0, op1)));
2862 }
2863
2864 return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));
2865}
2866\f
2867/* Return nonzero iff C has exactly one bit set if it is interpreted
942fd98f 2868 as a 32-bit constant. */
0d4a78eb
BS
2869
2870int
2871log2constp (unsigned HOST_WIDE_INT c)
2872{
2873 c &= 0xFFFFFFFF;
2874 return c != 0 && (c & (c-1)) == 0;
2875}
2876
2877/* Returns the number of consecutive least significant zeros in the binary
2878 representation of *V.
2879 We modify *V to contain the original value arithmetically shifted right by
2880 the number of zeroes. */
2881
2882static int
2883shiftr_zero (HOST_WIDE_INT *v)
2884{
2885 unsigned HOST_WIDE_INT tmp = *v;
2886 unsigned HOST_WIDE_INT sgn;
2887 int n = 0;
2888
2889 if (tmp == 0)
2890 return 0;
2891
2892 sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1));
2893 while ((tmp & 0x1) == 0 && n <= 32)
2894 {
2895 tmp = (tmp >> 1) | sgn;
2896 n++;
2897 }
2898 *v = tmp;
2899 return n;
2900}
2901
2902/* After reload, split the load of an immediate constant. OPERANDS are the
2903 operands of the movsi_insn pattern which we are splitting. We return
2904 nonzero if we emitted a sequence to load the constant, zero if we emitted
2905 nothing because we want to use the splitter's default sequence. */
2906
2907int
2908split_load_immediate (rtx operands[])
2909{
2910 HOST_WIDE_INT val = INTVAL (operands[1]);
2911 HOST_WIDE_INT tmp;
2912 HOST_WIDE_INT shifted = val;
2913 HOST_WIDE_INT shifted_compl = ~val;
2914 int num_zero = shiftr_zero (&shifted);
2915 int num_compl_zero = shiftr_zero (&shifted_compl);
2916 unsigned int regno = REGNO (operands[0]);
0d4a78eb
BS
2917
2918 /* This case takes care of single-bit set/clear constants, which we could
2919 also implement with BITSET/BITCLR. */
2920 if (num_zero
2921 && shifted >= -32768 && shifted < 65536
2922 && (D_REGNO_P (regno)
2923 || (regno >= REG_P0 && regno <= REG_P7 && num_zero <= 2)))
2924 {
2925 emit_insn (gen_movsi (operands[0], GEN_INT (shifted)));
2926 emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_zero)));
2927 return 1;
2928 }
2929
2930 tmp = val & 0xFFFF;
2931 tmp |= -(tmp & 0x8000);
2932
2933 /* If high word has one bit set or clear, try to use a bit operation. */
2934 if (D_REGNO_P (regno))
2935 {
2936 if (log2constp (val & 0xFFFF0000))
2937 {
2938 emit_insn (gen_movsi (operands[0], GEN_INT (val & 0xFFFF)));
2939 emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (val & 0xFFFF0000)));
2940 return 1;
2941 }
2942 else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0)
2943 {
2944 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2945 emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF)));
2946 }
2947 }
2948
2949 if (D_REGNO_P (regno))
2950 {
9fdd7520 2951 if (tmp >= -64 && tmp <= 63)
0d4a78eb
BS
2952 {
2953 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2954 emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536)));
2955 return 1;
2956 }
2957
2958 if ((val & 0xFFFF0000) == 0)
2959 {
2960 emit_insn (gen_movsi (operands[0], const0_rtx));
2961 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2962 return 1;
2963 }
2964
2965 if ((val & 0xFFFF0000) == 0xFFFF0000)
2966 {
2967 emit_insn (gen_movsi (operands[0], constm1_rtx));
2968 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2969 return 1;
2970 }
2971 }
2972
2973 /* Need DREGs for the remaining case. */
2974 if (regno > REG_R7)
2975 return 0;
2976
2977 if (optimize_size
9fdd7520 2978 && num_compl_zero && shifted_compl >= -64 && shifted_compl <= 63)
0d4a78eb
BS
2979 {
2980 /* If optimizing for size, generate a sequence that has more instructions
2981 but is shorter. */
2982 emit_insn (gen_movsi (operands[0], GEN_INT (shifted_compl)));
2983 emit_insn (gen_ashlsi3 (operands[0], operands[0],
2984 GEN_INT (num_compl_zero)));
2985 emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
2986 return 1;
2987 }
2988 return 0;
2989}
2990\f
2991/* Return true if the legitimate memory address for a memory operand of mode
2992 MODE. Return false if not. */
2993
2994static bool
2995bfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value)
2996{
2997 unsigned HOST_WIDE_INT v = value > 0 ? value : -value;
2998 int sz = GET_MODE_SIZE (mode);
2999 int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2;
3000 /* The usual offsettable_memref machinery doesn't work so well for this
3001 port, so we deal with the problem here. */
5308e943
BS
3002 if (value > 0 && sz == 8)
3003 v += 4;
3004 return (v & ~(0x7fff << shift)) == 0;
0d4a78eb
BS
3005}
3006
3007static bool
c4963a0a
BS
3008bfin_valid_reg_p (unsigned int regno, int strict, enum machine_mode mode,
3009 enum rtx_code outer_code)
0d4a78eb 3010{
c4963a0a
BS
3011 if (strict)
3012 return REGNO_OK_FOR_BASE_STRICT_P (regno, mode, outer_code, SCRATCH);
3013 else
3014 return REGNO_OK_FOR_BASE_NONSTRICT_P (regno, mode, outer_code, SCRATCH);
0d4a78eb
BS
3015}
3016
c6c3dba9
PB
3017/* Recognize an RTL expression that is a valid memory address for an
3018 instruction. The MODE argument is the machine mode for the MEM expression
3019 that wants to use this address.
3020
3021 Blackfin addressing modes are as follows:
3022
3023 [preg]
3024 [preg + imm16]
3025
3026 B [ Preg + uimm15 ]
3027 W [ Preg + uimm16m2 ]
3028 [ Preg + uimm17m4 ]
3029
3030 [preg++]
3031 [preg--]
3032 [--sp]
3033*/
3034
3035static bool
3036bfin_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
0d4a78eb
BS
3037{
3038 switch (GET_CODE (x)) {
3039 case REG:
c4963a0a 3040 if (bfin_valid_reg_p (REGNO (x), strict, mode, MEM))
0d4a78eb
BS
3041 return true;
3042 break;
3043 case PLUS:
3044 if (REG_P (XEXP (x, 0))
c4963a0a 3045 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PLUS)
300adfc2 3046 && ((GET_CODE (XEXP (x, 1)) == UNSPEC && mode == SImode)
0d4a78eb
BS
3047 || (GET_CODE (XEXP (x, 1)) == CONST_INT
3048 && bfin_valid_add (mode, INTVAL (XEXP (x, 1))))))
3049 return true;
3050 break;
3051 case POST_INC:
3052 case POST_DEC:
3053 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
3054 && REG_P (XEXP (x, 0))
c4963a0a 3055 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, POST_INC))
0d4a78eb
BS
3056 return true;
3057 case PRE_DEC:
3058 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
3059 && XEXP (x, 0) == stack_pointer_rtx
3060 && REG_P (XEXP (x, 0))
c4963a0a 3061 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PRE_DEC))
0d4a78eb
BS
3062 return true;
3063 break;
3064 default:
3065 break;
3066 }
3067 return false;
3068}
3069
d6f6753e
BS
3070/* Decide whether we can force certain constants to memory. If we
3071 decide we can't, the caller should be able to cope with it in
3072 another way. */
3073
3074static bool
3075bfin_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
3076{
3077 /* We have only one class of non-legitimate constants, and our movsi
3078 expander knows how to handle them. Dropping these constants into the
3079 data section would only shift the problem - we'd still get relocs
3080 outside the object, in the data section rather than the text section. */
3081 return true;
3082}
3083
3084/* Ensure that for any constant of the form symbol + offset, the offset
3085 remains within the object. Any other constants are ok.
3086 This ensures that flat binaries never have to deal with relocations
3087 crossing section boundaries. */
3088
3089bool
3090bfin_legitimate_constant_p (rtx x)
3091{
3092 rtx sym;
3093 HOST_WIDE_INT offset;
3094
3095 if (GET_CODE (x) != CONST)
3096 return true;
3097
3098 x = XEXP (x, 0);
3099 gcc_assert (GET_CODE (x) == PLUS);
3100
3101 sym = XEXP (x, 0);
3102 x = XEXP (x, 1);
3103 if (GET_CODE (sym) != SYMBOL_REF
3104 || GET_CODE (x) != CONST_INT)
3105 return true;
3106 offset = INTVAL (x);
3107
3108 if (SYMBOL_REF_DECL (sym) == 0)
3109 return true;
3110 if (offset < 0
3111 || offset >= int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (sym))))
3112 return false;
3113
3114 return true;
3115}
3116
0d4a78eb 3117static bool
d3c176fc 3118bfin_rtx_costs (rtx x, int code_i, int outer_code_i, int *total, bool speed)
0d4a78eb 3119{
d3c176fc
JR
3120 enum rtx_code code = (enum rtx_code) code_i;
3121 enum rtx_code outer_code = (enum rtx_code) outer_code_i;
0d4a78eb 3122 int cost2 = COSTS_N_INSNS (1);
4b53c508 3123 rtx op0, op1;
0d4a78eb
BS
3124
3125 switch (code)
3126 {
3127 case CONST_INT:
3128 if (outer_code == SET || outer_code == PLUS)
9fdd7520 3129 *total = satisfies_constraint_Ks7 (x) ? 0 : cost2;
0d4a78eb
BS
3130 else if (outer_code == AND)
3131 *total = log2constp (~INTVAL (x)) ? 0 : cost2;
3132 else if (outer_code == LE || outer_code == LT || outer_code == EQ)
3133 *total = (INTVAL (x) >= -4 && INTVAL (x) <= 3) ? 0 : cost2;
3134 else if (outer_code == LEU || outer_code == LTU)
3135 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 7) ? 0 : cost2;
3136 else if (outer_code == MULT)
3137 *total = (INTVAL (x) == 2 || INTVAL (x) == 4) ? 0 : cost2;
3138 else if (outer_code == ASHIFT && (INTVAL (x) == 1 || INTVAL (x) == 2))
3139 *total = 0;
3140 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
3141 || outer_code == LSHIFTRT)
3142 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 31) ? 0 : cost2;
3143 else if (outer_code == IOR || outer_code == XOR)
3144 *total = (INTVAL (x) & (INTVAL (x) - 1)) == 0 ? 0 : cost2;
3145 else
3146 *total = cost2;
3147 return true;
3148
3149 case CONST:
3150 case LABEL_REF:
3151 case SYMBOL_REF:
3152 case CONST_DOUBLE:
3153 *total = COSTS_N_INSNS (2);
3154 return true;
3155
3156 case PLUS:
4b53c508
BS
3157 op0 = XEXP (x, 0);
3158 op1 = XEXP (x, 1);
3159 if (GET_MODE (x) == SImode)
0d4a78eb 3160 {
4b53c508
BS
3161 if (GET_CODE (op0) == MULT
3162 && GET_CODE (XEXP (op0, 1)) == CONST_INT)
0d4a78eb 3163 {
4b53c508 3164 HOST_WIDE_INT val = INTVAL (XEXP (op0, 1));
0d4a78eb
BS
3165 if (val == 2 || val == 4)
3166 {
3167 *total = cost2;
f40751dd
JH
3168 *total += rtx_cost (XEXP (op0, 0), outer_code, speed);
3169 *total += rtx_cost (op1, outer_code, speed);
0d4a78eb
BS
3170 return true;
3171 }
3172 }
4b53c508
BS
3173 *total = cost2;
3174 if (GET_CODE (op0) != REG
3175 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
f40751dd 3176 *total += rtx_cost (op0, SET, speed);
4b53c508
BS
3177#if 0 /* We'd like to do this for accuracy, but it biases the loop optimizer
3178 towards creating too many induction variables. */
3179 if (!reg_or_7bit_operand (op1, SImode))
f40751dd 3180 *total += rtx_cost (op1, SET, speed);
4b53c508 3181#endif
0d4a78eb 3182 }
4b53c508
BS
3183 else if (GET_MODE (x) == DImode)
3184 {
3185 *total = 6 * cost2;
3186 if (GET_CODE (op1) != CONST_INT
9fdd7520 3187 || !satisfies_constraint_Ks7 (op1))
f40751dd 3188 *total += rtx_cost (op1, PLUS, speed);
4b53c508
BS
3189 if (GET_CODE (op0) != REG
3190 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
f40751dd 3191 *total += rtx_cost (op0, PLUS, speed);
4b53c508
BS
3192 }
3193 return true;
0d4a78eb
BS
3194
3195 case MINUS:
4b53c508
BS
3196 if (GET_MODE (x) == DImode)
3197 *total = 6 * cost2;
3198 else
3199 *total = cost2;
3200 return true;
3201
0d4a78eb
BS
3202 case ASHIFT:
3203 case ASHIFTRT:
3204 case LSHIFTRT:
3205 if (GET_MODE (x) == DImode)
3206 *total = 6 * cost2;
4b53c508
BS
3207 else
3208 *total = cost2;
3209
3210 op0 = XEXP (x, 0);
3211 op1 = XEXP (x, 1);
3212 if (GET_CODE (op0) != REG
3213 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
f40751dd 3214 *total += rtx_cost (op0, code, speed);
4b53c508
BS
3215
3216 return true;
0d4a78eb 3217
0d4a78eb 3218 case IOR:
4b53c508 3219 case AND:
0d4a78eb 3220 case XOR:
4b53c508
BS
3221 op0 = XEXP (x, 0);
3222 op1 = XEXP (x, 1);
3223
3224 /* Handle special cases of IOR: rotates, ALIGN insns, movstricthi_high. */
3225 if (code == IOR)
3226 {
3227 if ((GET_CODE (op0) == LSHIFTRT && GET_CODE (op1) == ASHIFT)
3228 || (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == ZERO_EXTEND)
3229 || (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == LSHIFTRT)
3230 || (GET_CODE (op0) == AND && GET_CODE (op1) == CONST_INT))
3231 {
3232 *total = cost2;
3233 return true;
3234 }
3235 }
3236
3237 if (GET_CODE (op0) != REG
3238 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
f40751dd 3239 *total += rtx_cost (op0, code, speed);
4b53c508 3240
0d4a78eb 3241 if (GET_MODE (x) == DImode)
4b53c508
BS
3242 {
3243 *total = 2 * cost2;
3244 return true;
3245 }
3246 *total = cost2;
3247 if (GET_MODE (x) != SImode)
3248 return true;
3249
3250 if (code == AND)
3251 {
3252 if (! rhs_andsi3_operand (XEXP (x, 1), SImode))
f40751dd 3253 *total += rtx_cost (XEXP (x, 1), code, speed);
4b53c508
BS
3254 }
3255 else
3256 {
3257 if (! regorlog2_operand (XEXP (x, 1), SImode))
f40751dd 3258 *total += rtx_cost (XEXP (x, 1), code, speed);
4b53c508
BS
3259 }
3260
3261 return true;
3262
3263 case ZERO_EXTRACT:
3264 case SIGN_EXTRACT:
3265 if (outer_code == SET
3266 && XEXP (x, 1) == const1_rtx
3267 && GET_CODE (XEXP (x, 2)) == CONST_INT)
3268 {
3269 *total = 2 * cost2;
3270 return true;
3271 }
3272 /* fall through */
3273
3274 case SIGN_EXTEND:
3275 case ZERO_EXTEND:
3276 *total = cost2;
3277 return true;
0d4a78eb
BS
3278
3279 case MULT:
4b53c508
BS
3280 {
3281 op0 = XEXP (x, 0);
3282 op1 = XEXP (x, 1);
3283 if (GET_CODE (op0) == GET_CODE (op1)
3284 && (GET_CODE (op0) == ZERO_EXTEND
3285 || GET_CODE (op0) == SIGN_EXTEND))
3286 {
3287 *total = COSTS_N_INSNS (1);
3288 op0 = XEXP (op0, 0);
3289 op1 = XEXP (op1, 0);
3290 }
f40751dd 3291 else if (!speed)
4b53c508
BS
3292 *total = COSTS_N_INSNS (1);
3293 else
3294 *total = COSTS_N_INSNS (3);
3295
3296 if (GET_CODE (op0) != REG
3297 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
f40751dd 3298 *total += rtx_cost (op0, MULT, speed);
4b53c508
BS
3299 if (GET_CODE (op1) != REG
3300 && (GET_CODE (op1) != SUBREG || GET_CODE (SUBREG_REG (op1)) != REG))
f40751dd 3301 *total += rtx_cost (op1, MULT, speed);
4b53c508
BS
3302 }
3303 return true;
0d4a78eb 3304
61066abf
BS
3305 case UDIV:
3306 case UMOD:
3307 *total = COSTS_N_INSNS (32);
3308 return true;
3309
42da70b7
BS
3310 case VEC_CONCAT:
3311 case VEC_SELECT:
3312 if (outer_code == SET)
3313 *total = cost2;
3314 return true;
3315
0d4a78eb
BS
3316 default:
3317 return false;
3318 }
3319}
0d4a78eb
BS
3320\f
3321/* Used for communication between {push,pop}_multiple_operation (which
3322 we use not only as a predicate) and the corresponding output functions. */
3323static int first_preg_to_save, first_dreg_to_save;
22fb24d5 3324static int n_regs_to_save;
0d4a78eb
BS
3325
3326int
3327push_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3328{
3329 int lastdreg = 8, lastpreg = 6;
3330 int i, group;
3331
3332 first_preg_to_save = lastpreg;
3333 first_dreg_to_save = lastdreg;
3334 for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++)
3335 {
3336 rtx t = XVECEXP (op, 0, i);
3337 rtx src, dest;
3338 int regno;
3339
3340 if (GET_CODE (t) != SET)
3341 return 0;
3342
3343 src = SET_SRC (t);
3344 dest = SET_DEST (t);
3345 if (GET_CODE (dest) != MEM || ! REG_P (src))
3346 return 0;
3347 dest = XEXP (dest, 0);
3348 if (GET_CODE (dest) != PLUS
3349 || ! REG_P (XEXP (dest, 0))
3350 || REGNO (XEXP (dest, 0)) != REG_SP
3351 || GET_CODE (XEXP (dest, 1)) != CONST_INT
3352 || INTVAL (XEXP (dest, 1)) != -i * 4)
3353 return 0;
3354
3355 regno = REGNO (src);
3356 if (group == 0)
3357 {
3358 if (D_REGNO_P (regno))
3359 {
3360 group = 1;
3361 first_dreg_to_save = lastdreg = regno - REG_R0;
3362 }
3363 else if (regno >= REG_P0 && regno <= REG_P7)
3364 {
3365 group = 2;
3366 first_preg_to_save = lastpreg = regno - REG_P0;
3367 }
3368 else
3369 return 0;
3370
3371 continue;
3372 }
3373
3374 if (group == 1)
3375 {
3376 if (regno >= REG_P0 && regno <= REG_P7)
3377 {
3378 group = 2;
3379 first_preg_to_save = lastpreg = regno - REG_P0;
3380 }
3381 else if (regno != REG_R0 + lastdreg + 1)
3382 return 0;
3383 else
3384 lastdreg++;
3385 }
3386 else if (group == 2)
3387 {
3388 if (regno != REG_P0 + lastpreg + 1)
3389 return 0;
3390 lastpreg++;
3391 }
3392 }
22fb24d5 3393 n_regs_to_save = 8 - first_dreg_to_save + 6 - first_preg_to_save;
0d4a78eb
BS
3394 return 1;
3395}
3396
3397int
3398pop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3399{
3400 int lastdreg = 8, lastpreg = 6;
3401 int i, group;
3402
3403 for (i = 1, group = 0; i < XVECLEN (op, 0); i++)
3404 {
3405 rtx t = XVECEXP (op, 0, i);
3406 rtx src, dest;
3407 int regno;
3408
3409 if (GET_CODE (t) != SET)
3410 return 0;
3411
3412 src = SET_SRC (t);
3413 dest = SET_DEST (t);
3414 if (GET_CODE (src) != MEM || ! REG_P (dest))
3415 return 0;
3416 src = XEXP (src, 0);
3417
3418 if (i == 1)
3419 {
3420 if (! REG_P (src) || REGNO (src) != REG_SP)
3421 return 0;
3422 }
3423 else if (GET_CODE (src) != PLUS
3424 || ! REG_P (XEXP (src, 0))
3425 || REGNO (XEXP (src, 0)) != REG_SP
3426 || GET_CODE (XEXP (src, 1)) != CONST_INT
3427 || INTVAL (XEXP (src, 1)) != (i - 1) * 4)
3428 return 0;
3429
3430 regno = REGNO (dest);
3431 if (group == 0)
3432 {
3433 if (regno == REG_R7)
3434 {
3435 group = 1;
3436 lastdreg = 7;
3437 }
3438 else if (regno != REG_P0 + lastpreg - 1)
3439 return 0;
3440 else
3441 lastpreg--;
3442 }
3443 else if (group == 1)
3444 {
3445 if (regno != REG_R0 + lastdreg - 1)
3446 return 0;
3447 else
3448 lastdreg--;
3449 }
3450 }
3451 first_dreg_to_save = lastdreg;
3452 first_preg_to_save = lastpreg;
22fb24d5 3453 n_regs_to_save = 8 - first_dreg_to_save + 6 - first_preg_to_save;
0d4a78eb
BS
3454 return 1;
3455}
3456
3457/* Emit assembly code for one multi-register push described by INSN, with
3458 operands in OPERANDS. */
3459
3460void
3461output_push_multiple (rtx insn, rtx *operands)
3462{
3463 char buf[80];
3b9dd769
NS
3464 int ok;
3465
0d4a78eb 3466 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3b9dd769
NS
3467 ok = push_multiple_operation (PATTERN (insn), VOIDmode);
3468 gcc_assert (ok);
3469
0d4a78eb
BS
3470 if (first_dreg_to_save == 8)
3471 sprintf (buf, "[--sp] = ( p5:%d );\n", first_preg_to_save);
3472 else if (first_preg_to_save == 6)
3473 sprintf (buf, "[--sp] = ( r7:%d );\n", first_dreg_to_save);
3474 else
3b9dd769
NS
3475 sprintf (buf, "[--sp] = ( r7:%d, p5:%d );\n",
3476 first_dreg_to_save, first_preg_to_save);
0d4a78eb
BS
3477
3478 output_asm_insn (buf, operands);
3479}
3480
3481/* Emit assembly code for one multi-register pop described by INSN, with
3482 operands in OPERANDS. */
3483
3484void
3485output_pop_multiple (rtx insn, rtx *operands)
3486{
3487 char buf[80];
3b9dd769
NS
3488 int ok;
3489
0d4a78eb 3490 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3b9dd769
NS
3491 ok = pop_multiple_operation (PATTERN (insn), VOIDmode);
3492 gcc_assert (ok);
0d4a78eb
BS
3493
3494 if (first_dreg_to_save == 8)
3495 sprintf (buf, "( p5:%d ) = [sp++];\n", first_preg_to_save);
3496 else if (first_preg_to_save == 6)
3497 sprintf (buf, "( r7:%d ) = [sp++];\n", first_dreg_to_save);
3498 else
3b9dd769
NS
3499 sprintf (buf, "( r7:%d, p5:%d ) = [sp++];\n",
3500 first_dreg_to_save, first_preg_to_save);
0d4a78eb
BS
3501
3502 output_asm_insn (buf, operands);
3503}
3504
3505/* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */
3506
3507static void
144f8315 3508single_move_for_movmem (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset)
0d4a78eb
BS
3509{
3510 rtx scratch = gen_reg_rtx (mode);
3511 rtx srcmem, dstmem;
3512
3513 srcmem = adjust_address_nv (src, mode, offset);
3514 dstmem = adjust_address_nv (dst, mode, offset);
3515 emit_move_insn (scratch, srcmem);
3516 emit_move_insn (dstmem, scratch);
3517}
3518
3519/* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
3520 alignment ALIGN_EXP. Return true if successful, false if we should fall
3521 back on a different method. */
3522
3523bool
144f8315 3524bfin_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp)
0d4a78eb
BS
3525{
3526 rtx srcreg, destreg, countreg;
3527 HOST_WIDE_INT align = 0;
3528 unsigned HOST_WIDE_INT count = 0;
3529
3530 if (GET_CODE (align_exp) == CONST_INT)
3531 align = INTVAL (align_exp);
3532 if (GET_CODE (count_exp) == CONST_INT)
3533 {
3534 count = INTVAL (count_exp);
3535#if 0
3536 if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
3537 return false;
3538#endif
3539 }
3540
3541 /* If optimizing for size, only do single copies inline. */
3542 if (optimize_size)
3543 {
3544 if (count == 2 && align < 2)
3545 return false;
3546 if (count == 4 && align < 4)
3547 return false;
3548 if (count != 1 && count != 2 && count != 4)
3549 return false;
3550 }
3551 if (align < 2 && count != 1)
3552 return false;
3553
3554 destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
3555 if (destreg != XEXP (dst, 0))
3556 dst = replace_equiv_address_nv (dst, destreg);
3557 srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0));
3558 if (srcreg != XEXP (src, 0))
3559 src = replace_equiv_address_nv (src, srcreg);
3560
3561 if (count != 0 && align >= 2)
3562 {
3563 unsigned HOST_WIDE_INT offset = 0;
3564
3565 if (align >= 4)
3566 {
3567 if ((count & ~3) == 4)
3568 {
144f8315 3569 single_move_for_movmem (dst, src, SImode, offset);
0d4a78eb
BS
3570 offset = 4;
3571 }
3572 else if (count & ~3)
3573 {
3574 HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1;
3575 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3576
3577 emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg));
a848cf52 3578 cfun->machine->has_loopreg_clobber = true;
0d4a78eb 3579 }
51a641fd
JZ
3580 if (count & 2)
3581 {
144f8315 3582 single_move_for_movmem (dst, src, HImode, offset);
51a641fd
JZ
3583 offset += 2;
3584 }
0d4a78eb
BS
3585 }
3586 else
3587 {
3588 if ((count & ~1) == 2)
3589 {
144f8315 3590 single_move_for_movmem (dst, src, HImode, offset);
0d4a78eb
BS
3591 offset = 2;
3592 }
3593 else if (count & ~1)
3594 {
3595 HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1;
3596 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3597
3598 emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg));
a848cf52 3599 cfun->machine->has_loopreg_clobber = true;
0d4a78eb
BS
3600 }
3601 }
0d4a78eb
BS
3602 if (count & 1)
3603 {
144f8315 3604 single_move_for_movmem (dst, src, QImode, offset);
0d4a78eb
BS
3605 }
3606 return true;
3607 }
3608 return false;
3609}
0d4a78eb 3610\f
520c62ad
BS
3611/* Compute the alignment for a local variable.
3612 TYPE is the data type, and ALIGN is the alignment that
3613 the object would ordinarily have. The value of this macro is used
3614 instead of that alignment to align the object. */
3615
d3c176fc
JR
3616unsigned
3617bfin_local_alignment (tree type, unsigned align)
520c62ad
BS
3618{
3619 /* Increasing alignment for (relatively) big types allows the builtin
3620 memcpy can use 32 bit loads/stores. */
3621 if (TYPE_SIZE (type)
3622 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
3623 && (TREE_INT_CST_LOW (TYPE_SIZE (type)) > 8
3624 || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 32)
3625 return 32;
3626 return align;
3627}
3628\f
36662eb1
BS
3629/* Implement TARGET_SCHED_ISSUE_RATE. */
3630
3631static int
3632bfin_issue_rate (void)
3633{
3634 return 3;
3635}
3636
0d4a78eb
BS
3637static int
3638bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
3639{
d3c176fc 3640 enum attr_type dep_insn_type;
0d4a78eb
BS
3641 int dep_insn_code_number;
3642
3643 /* Anti and output dependencies have zero cost. */
3644 if (REG_NOTE_KIND (link) != 0)
3645 return 0;
3646
3647 dep_insn_code_number = recog_memoized (dep_insn);
3648
3649 /* If we can't recognize the insns, we can't really do anything. */
3650 if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
3651 return cost;
3652
0d4a78eb
BS
3653 dep_insn_type = get_attr_type (dep_insn);
3654
3655 if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
3656 {
3657 rtx pat = PATTERN (dep_insn);
d3c176fc
JR
3658 rtx dest, src;
3659
86636093
RIL
3660 if (GET_CODE (pat) == PARALLEL)
3661 pat = XVECEXP (pat, 0, 0);
d3c176fc
JR
3662 dest = SET_DEST (pat);
3663 src = SET_SRC (pat);
96f46444
BS
3664 if (! ADDRESS_REGNO_P (REGNO (dest))
3665 || ! (MEM_P (src) || D_REGNO_P (REGNO (src))))
0d4a78eb
BS
3666 return cost;
3667 return cost + (dep_insn_type == TYPE_MOVE ? 4 : 3);
3668 }
3669
3670 return cost;
3671}
dd2139e7
BS
3672\f
3673/* This function acts like NEXT_INSN, but is aware of three-insn bundles and
3674 skips all subsequent parallel instructions if INSN is the start of such
3675 a group. */
3676static rtx
3677find_next_insn_start (rtx insn)
3678{
3679 if (GET_MODE (insn) == SImode)
3680 {
3681 while (GET_MODE (insn) != QImode)
3682 insn = NEXT_INSN (insn);
3683 }
3684 return NEXT_INSN (insn);
3685}
b03149e1 3686
dd2139e7
BS
3687/* This function acts like PREV_INSN, but is aware of three-insn bundles and
3688 skips all subsequent parallel instructions if INSN is the start of such
3689 a group. */
3690static rtx
3691find_prev_insn_start (rtx insn)
3692{
3693 insn = PREV_INSN (insn);
3694 gcc_assert (GET_MODE (insn) != SImode);
3695 if (GET_MODE (insn) == QImode)
3696 {
3697 while (GET_MODE (PREV_INSN (insn)) == SImode)
3698 insn = PREV_INSN (insn);
3699 }
3700 return insn;
3701}
b03149e1
JZ
3702\f
3703/* Increment the counter for the number of loop instructions in the
3704 current function. */
3705
3706void
3707bfin_hardware_loop (void)
3708{
3709 cfun->machine->has_hardware_loops++;
3710}
3711
aab26080 3712/* Maximum loop nesting depth. */
b03149e1
JZ
3713#define MAX_LOOP_DEPTH 2
3714
aab26080 3715/* Maximum size of a loop. */
40327e03 3716#define MAX_LOOP_LENGTH 2042
b03149e1 3717
ce27ef3d
BS
3718/* Maximum distance of the LSETUP instruction from the loop start. */
3719#define MAX_LSETUP_DISTANCE 30
3720
b03149e1 3721/* We need to keep a vector of loops */
d3c176fc 3722typedef struct loop_info_d *loop_info;
b03149e1
JZ
3723DEF_VEC_P (loop_info);
3724DEF_VEC_ALLOC_P (loop_info,heap);
3725
3726/* Information about a loop we have found (or are in the process of
3727 finding). */
d3c176fc 3728struct GTY (()) loop_info_d
b03149e1
JZ
3729{
3730 /* loop number, for dumps */
3731 int loop_no;
3732
ce27ef3d
BS
3733 /* All edges that jump into and out of the loop. */
3734 VEC(edge,gc) *incoming;
3735
3736 /* We can handle two cases: all incoming edges have the same destination
3737 block, or all incoming edges have the same source block. These two
3738 members are set to the common source or destination we found, or NULL
3739 if different blocks were found. If both are NULL the loop can't be
3740 optimized. */
3741 basic_block incoming_src;
3742 basic_block incoming_dest;
b03149e1
JZ
3743
3744 /* First block in the loop. This is the one branched to by the loop_end
3745 insn. */
3746 basic_block head;
3747
3748 /* Last block in the loop (the one with the loop_end insn). */
3749 basic_block tail;
3750
3751 /* The successor block of the loop. This is the one the loop_end insn
3752 falls into. */
3753 basic_block successor;
3754
3755 /* The last instruction in the tail. */
3756 rtx last_insn;
3757
3758 /* The loop_end insn. */
3759 rtx loop_end;
3760
3761 /* The iteration register. */
3762 rtx iter_reg;
3763
b03149e1
JZ
3764 /* The new label placed at the beginning of the loop. */
3765 rtx start_label;
3766
3767 /* The new label placed at the end of the loop. */
3768 rtx end_label;
3769
3770 /* The length of the loop. */
3771 int length;
3772
e54273eb 3773 /* The nesting depth of the loop. */
b03149e1
JZ
3774 int depth;
3775
e54273eb
BS
3776 /* Nonzero if we can't optimize this loop. */
3777 int bad;
3778
b03149e1
JZ
3779 /* True if we have visited this loop. */
3780 int visited;
3781
3782 /* True if this loop body clobbers any of LC0, LT0, or LB0. */
3783 int clobber_loop0;
3784
3785 /* True if this loop body clobbers any of LC1, LT1, or LB1. */
3786 int clobber_loop1;
3787
3788 /* Next loop in the graph. */
d3c176fc 3789 struct loop_info_d *next;
b03149e1
JZ
3790
3791 /* Immediate outer loop of this loop. */
d3c176fc 3792 struct loop_info_d *outer;
b03149e1 3793
e54273eb
BS
3794 /* Vector of blocks only within the loop, including those within
3795 inner loops. */
b03149e1
JZ
3796 VEC (basic_block,heap) *blocks;
3797
e54273eb
BS
3798 /* Same information in a bitmap. */
3799 bitmap block_bitmap;
3800
b03149e1
JZ
3801 /* Vector of inner loops within this loop */
3802 VEC (loop_info,heap) *loops;
3803};
3804
b03149e1
JZ
3805static void
3806bfin_dump_loops (loop_info loops)
3807{
3808 loop_info loop;
3809
3810 for (loop = loops; loop; loop = loop->next)
3811 {
3812 loop_info i;
3813 basic_block b;
3814 unsigned ix;
3815
3816 fprintf (dump_file, ";; loop %d: ", loop->loop_no);
e54273eb
BS
3817 if (loop->bad)
3818 fprintf (dump_file, "(bad) ");
b03149e1
JZ
3819 fprintf (dump_file, "{head:%d, depth:%d}", loop->head->index, loop->depth);
3820
3821 fprintf (dump_file, " blocks: [ ");
ac47786e 3822 FOR_EACH_VEC_ELT (basic_block, loop->blocks, ix, b)
b03149e1
JZ
3823 fprintf (dump_file, "%d ", b->index);
3824 fprintf (dump_file, "] ");
3825
3826 fprintf (dump_file, " inner loops: [ ");
ac47786e 3827 FOR_EACH_VEC_ELT (loop_info, loop->loops, ix, i)
b03149e1
JZ
3828 fprintf (dump_file, "%d ", i->loop_no);
3829 fprintf (dump_file, "]\n");
3830 }
3831 fprintf (dump_file, "\n");
3832}
3833
3834/* Scan the blocks of LOOP (and its inferiors) looking for basic block
3835 BB. Return true, if we find it. */
3836
3837static bool
3838bfin_bb_in_loop (loop_info loop, basic_block bb)
3839{
e54273eb 3840 return bitmap_bit_p (loop->block_bitmap, bb->index);
b03149e1
JZ
3841}
3842
3843/* Scan the blocks of LOOP (and its inferiors) looking for uses of
3844 REG. Return true, if we find any. Don't count the loop's loop_end
3845 insn if it matches LOOP_END. */
3846
3847static bool
3848bfin_scan_loop (loop_info loop, rtx reg, rtx loop_end)
3849{
3850 unsigned ix;
b03149e1
JZ
3851 basic_block bb;
3852
ac47786e 3853 FOR_EACH_VEC_ELT (basic_block, loop->blocks, ix, bb)
b03149e1
JZ
3854 {
3855 rtx insn;
3856
3857 for (insn = BB_HEAD (bb);
3858 insn != NEXT_INSN (BB_END (bb));
3859 insn = NEXT_INSN (insn))
3860 {
3861 if (!INSN_P (insn))
3862 continue;
3863 if (insn == loop_end)
3864 continue;
3865 if (reg_mentioned_p (reg, PATTERN (insn)))
3866 return true;
3867 }
3868 }
b03149e1
JZ
3869 return false;
3870}
3871
ce27ef3d
BS
3872/* Estimate the length of INSN conservatively. */
3873
3874static int
3875length_for_loop (rtx insn)
3876{
3877 int length = 0;
3878 if (JUMP_P (insn) && any_condjump_p (insn) && !optimize_size)
3879 {
ea2382be 3880 if (ENABLE_WA_SPECULATIVE_SYNCS)
ce27ef3d 3881 length = 8;
ea2382be 3882 else if (ENABLE_WA_SPECULATIVE_LOADS)
ce27ef3d
BS
3883 length = 6;
3884 }
3885 else if (LABEL_P (insn))
3886 {
ea2382be 3887 if (ENABLE_WA_SPECULATIVE_SYNCS)
ce27ef3d
BS
3888 length = 4;
3889 }
3890
e5e44796 3891 if (NONDEBUG_INSN_P (insn))
ce27ef3d
BS
3892 length += get_attr_length (insn);
3893
3894 return length;
3895}
3896
b03149e1
JZ
3897/* Optimize LOOP. */
3898
3899static void
3900bfin_optimize_loop (loop_info loop)
3901{
3902 basic_block bb;
e54273eb 3903 loop_info inner;
97a988bc 3904 rtx insn, last_insn;
b03149e1
JZ
3905 rtx loop_init, start_label, end_label;
3906 rtx reg_lc0, reg_lc1, reg_lt0, reg_lt1, reg_lb0, reg_lb1;
e50e3081 3907 rtx iter_reg, scratchreg, scratch_init, scratch_init_insn;
b03149e1 3908 rtx lc_reg, lt_reg, lb_reg;
ce27ef3d 3909 rtx seq, seq_end;
b03149e1
JZ
3910 int length;
3911 unsigned ix;
3912 int inner_depth = 0;
b03149e1
JZ
3913
3914 if (loop->visited)
3915 return;
3916
3917 loop->visited = 1;
3918
e54273eb 3919 if (loop->bad)
b03149e1
JZ
3920 {
3921 if (dump_file)
3922 fprintf (dump_file, ";; loop %d bad when found\n", loop->loop_no);
3923 goto bad_loop;
3924 }
3925
e54273eb
BS
3926 /* Every loop contains in its list of inner loops every loop nested inside
3927 it, even if there are intermediate loops. This works because we're doing
3928 a depth-first search here and never visit a loop more than once. */
ac47786e 3929 FOR_EACH_VEC_ELT (loop_info, loop->loops, ix, inner)
b03149e1 3930 {
e54273eb 3931 bfin_optimize_loop (inner);
b03149e1 3932
e54273eb
BS
3933 if (!inner->bad && inner_depth < inner->depth)
3934 {
3935 inner_depth = inner->depth;
b03149e1 3936
e54273eb
BS
3937 loop->clobber_loop0 |= inner->clobber_loop0;
3938 loop->clobber_loop1 |= inner->clobber_loop1;
3939 }
b03149e1
JZ
3940 }
3941
e54273eb
BS
3942 loop->depth = inner_depth + 1;
3943 if (loop->depth > MAX_LOOP_DEPTH)
b03149e1
JZ
3944 {
3945 if (dump_file)
e54273eb 3946 fprintf (dump_file, ";; loop %d too deep\n", loop->loop_no);
b03149e1
JZ
3947 goto bad_loop;
3948 }
3949
3950 /* Get the loop iteration register. */
3951 iter_reg = loop->iter_reg;
3952
97a988bc 3953 if (!REG_P (iter_reg))
b03149e1
JZ
3954 {
3955 if (dump_file)
97a988bc 3956 fprintf (dump_file, ";; loop %d iteration count not in a register\n",
b03149e1
JZ
3957 loop->loop_no);
3958 goto bad_loop;
3959 }
97a988bc 3960 scratchreg = NULL_RTX;
e50e3081
BS
3961 scratch_init = iter_reg;
3962 scratch_init_insn = NULL_RTX;
97a988bc
BS
3963 if (!PREG_P (iter_reg) && loop->incoming_src)
3964 {
e50e3081 3965 basic_block bb_in = loop->incoming_src;
97a988bc
BS
3966 int i;
3967 for (i = REG_P0; i <= REG_P5; i++)
3968 if ((df_regs_ever_live_p (i)
3969 || (funkind (TREE_TYPE (current_function_decl)) == SUBROUTINE
3970 && call_used_regs[i]))
e50e3081 3971 && !REGNO_REG_SET_P (df_get_live_out (bb_in), i))
97a988bc
BS
3972 {
3973 scratchreg = gen_rtx_REG (SImode, i);
3974 break;
3975 }
e50e3081
BS
3976 for (insn = BB_END (bb_in); insn != BB_HEAD (bb_in);
3977 insn = PREV_INSN (insn))
3978 {
3979 rtx set;
3980 if (NOTE_P (insn) || BARRIER_P (insn))
3981 continue;
3982 set = single_set (insn);
3983 if (set && rtx_equal_p (SET_DEST (set), iter_reg))
3984 {
3985 if (CONSTANT_P (SET_SRC (set)))
3986 {
3987 scratch_init = SET_SRC (set);
3988 scratch_init_insn = insn;
3989 }
3990 break;
3991 }
3992 else if (reg_mentioned_p (iter_reg, PATTERN (insn)))
3993 break;
3994 }
97a988bc 3995 }
b03149e1 3996
ce27ef3d
BS
3997 if (loop->incoming_src)
3998 {
3999 /* Make sure the predecessor is before the loop start label, as required by
4000 the LSETUP instruction. */
4001 length = 0;
03f8829b
BS
4002 insn = BB_END (loop->incoming_src);
4003 /* If we have to insert the LSETUP before a jump, count that jump in the
4004 length. */
4005 if (VEC_length (edge, loop->incoming) > 1
4006 || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
4007 {
4008 gcc_assert (JUMP_P (insn));
4009 insn = PREV_INSN (insn);
4010 }
4011
4012 for (; insn && insn != loop->start_label; insn = NEXT_INSN (insn))
ce27ef3d 4013 length += length_for_loop (insn);
97a988bc 4014
ce27ef3d
BS
4015 if (!insn)
4016 {
4017 if (dump_file)
4018 fprintf (dump_file, ";; loop %d lsetup not before loop_start\n",
4019 loop->loop_no);
4020 goto bad_loop;
4021 }
4022
97a988bc
BS
4023 /* Account for the pop of a scratch register where necessary. */
4024 if (!PREG_P (iter_reg) && scratchreg == NULL_RTX
4025 && ENABLE_WA_LOAD_LCREGS)
4026 length += 2;
4027
ce27ef3d
BS
4028 if (length > MAX_LSETUP_DISTANCE)
4029 {
4030 if (dump_file)
4031 fprintf (dump_file, ";; loop %d lsetup too far away\n", loop->loop_no);
4032 goto bad_loop;
4033 }
4034 }
4035
b03149e1
JZ
4036 /* Check if start_label appears before loop_end and calculate the
4037 offset between them. We calculate the length of instructions
4038 conservatively. */
4039 length = 0;
4040 for (insn = loop->start_label;
4041 insn && insn != loop->loop_end;
4042 insn = NEXT_INSN (insn))
ce27ef3d 4043 length += length_for_loop (insn);
b03149e1
JZ
4044
4045 if (!insn)
4046 {
4047 if (dump_file)
4048 fprintf (dump_file, ";; loop %d start_label not before loop_end\n",
4049 loop->loop_no);
4050 goto bad_loop;
4051 }
4052
4053 loop->length = length;
4054 if (loop->length > MAX_LOOP_LENGTH)
4055 {
4056 if (dump_file)
4057 fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
4058 goto bad_loop;
4059 }
4060
4061 /* Scan all the blocks to make sure they don't use iter_reg. */
4062 if (bfin_scan_loop (loop, iter_reg, loop->loop_end))
4063 {
4064 if (dump_file)
4065 fprintf (dump_file, ";; loop %d uses iterator\n", loop->loop_no);
4066 goto bad_loop;
4067 }
4068
4069 /* Scan all the insns to see if the loop body clobber
4070 any hardware loop registers. */
4071
4072 reg_lc0 = gen_rtx_REG (SImode, REG_LC0);
4073 reg_lc1 = gen_rtx_REG (SImode, REG_LC1);
4074 reg_lt0 = gen_rtx_REG (SImode, REG_LT0);
4075 reg_lt1 = gen_rtx_REG (SImode, REG_LT1);
4076 reg_lb0 = gen_rtx_REG (SImode, REG_LB0);
4077 reg_lb1 = gen_rtx_REG (SImode, REG_LB1);
4078
ac47786e 4079 FOR_EACH_VEC_ELT (basic_block, loop->blocks, ix, bb)
b03149e1
JZ
4080 {
4081 rtx insn;
4082
4083 for (insn = BB_HEAD (bb);
4084 insn != NEXT_INSN (BB_END (bb));
4085 insn = NEXT_INSN (insn))
4086 {
4087 if (!INSN_P (insn))
4088 continue;
4089
4090 if (reg_set_p (reg_lc0, insn)
4091 || reg_set_p (reg_lt0, insn)
4092 || reg_set_p (reg_lb0, insn))
4093 loop->clobber_loop0 = 1;
4094
4095 if (reg_set_p (reg_lc1, insn)
4096 || reg_set_p (reg_lt1, insn)
4097 || reg_set_p (reg_lb1, insn))
4098 loop->clobber_loop1 |= 1;
4099 }
4100 }
4101
4102 if ((loop->clobber_loop0 && loop->clobber_loop1)
4103 || (loop->depth == MAX_LOOP_DEPTH && loop->clobber_loop0))
4104 {
4105 loop->depth = MAX_LOOP_DEPTH + 1;
4106 if (dump_file)
4107 fprintf (dump_file, ";; loop %d no loop reg available\n",
4108 loop->loop_no);
4109 goto bad_loop;
4110 }
4111
4112 /* There should be an instruction before the loop_end instruction
4113 in the same basic block. And the instruction must not be
4114 - JUMP
4115 - CONDITIONAL BRANCH
4116 - CALL
4117 - CSYNC
4118 - SSYNC
4119 - Returns (RTS, RTN, etc.) */
4120
4121 bb = loop->tail;
dd2139e7 4122 last_insn = find_prev_insn_start (loop->loop_end);
b03149e1
JZ
4123
4124 while (1)
4125 {
dd2139e7
BS
4126 for (; last_insn != BB_HEAD (bb);
4127 last_insn = find_prev_insn_start (last_insn))
e5e44796 4128 if (NONDEBUG_INSN_P (last_insn))
b03149e1
JZ
4129 break;
4130
dd2139e7 4131 if (last_insn != BB_HEAD (bb))
b03149e1
JZ
4132 break;
4133
4134 if (single_pred_p (bb)
4e5d521b 4135 && single_pred_edge (bb)->flags & EDGE_FALLTHRU
b03149e1
JZ
4136 && single_pred (bb) != ENTRY_BLOCK_PTR)
4137 {
4138 bb = single_pred (bb);
4139 last_insn = BB_END (bb);
4140 continue;
4141 }
4142 else
4143 {
4144 last_insn = NULL_RTX;
4145 break;
4146 }
4147 }
4148
4149 if (!last_insn)
4150 {
4151 if (dump_file)
4152 fprintf (dump_file, ";; loop %d has no last instruction\n",
4153 loop->loop_no);
4154 goto bad_loop;
4155 }
4156
307e7eab 4157 if (JUMP_P (last_insn) && !any_condjump_p (last_insn))
b03149e1 4158 {
307e7eab
BS
4159 if (dump_file)
4160 fprintf (dump_file, ";; loop %d has bad last instruction\n",
4161 loop->loop_no);
4162 goto bad_loop;
4163 }
4164 /* In all other cases, try to replace a bad last insn with a nop. */
4165 else if (JUMP_P (last_insn)
4166 || CALL_P (last_insn)
4167 || get_attr_type (last_insn) == TYPE_SYNC
4168 || get_attr_type (last_insn) == TYPE_CALL
4169 || get_attr_seq_insns (last_insn) == SEQ_INSNS_MULTI
4170 || recog_memoized (last_insn) == CODE_FOR_return_internal
4171 || GET_CODE (PATTERN (last_insn)) == ASM_INPUT
4172 || asm_noperands (PATTERN (last_insn)) >= 0)
4173 {
4174 if (loop->length + 2 > MAX_LOOP_LENGTH)
b03149e1
JZ
4175 {
4176 if (dump_file)
307e7eab 4177 fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
b03149e1
JZ
4178 goto bad_loop;
4179 }
b03149e1 4180 if (dump_file)
307e7eab 4181 fprintf (dump_file, ";; loop %d has bad last insn; replace with nop\n",
b03149e1 4182 loop->loop_no);
b03149e1 4183
307e7eab 4184 last_insn = emit_insn_after (gen_forced_nop (), last_insn);
b03149e1
JZ
4185 }
4186
4187 loop->last_insn = last_insn;
4188
4189 /* The loop is good for replacement. */
4190 start_label = loop->start_label;
4191 end_label = gen_label_rtx ();
4192 iter_reg = loop->iter_reg;
4193
4194 if (loop->depth == 1 && !loop->clobber_loop1)
4195 {
4196 lc_reg = reg_lc1;
4197 lt_reg = reg_lt1;
4198 lb_reg = reg_lb1;
4199 loop->clobber_loop1 = 1;
4200 }
4201 else
4202 {
4203 lc_reg = reg_lc0;
4204 lt_reg = reg_lt0;
4205 lb_reg = reg_lb0;
4206 loop->clobber_loop0 = 1;
4207 }
4208
97a988bc
BS
4209 loop->end_label = end_label;
4210
4211 /* Create a sequence containing the loop setup. */
4212 start_sequence ();
4213
4214 /* LSETUP only accepts P registers. If we have one, we can use it,
4215 otherwise there are several ways of working around the problem.
4216 If we're not affected by anomaly 312, we can load the LC register
4217 from any iteration register, and use LSETUP without initialization.
4218 If we've found a P scratch register that's not live here, we can
4219 instead copy the iter_reg into that and use an initializing LSETUP.
4220 If all else fails, push and pop P0 and use it as a scratch. */
4221 if (P_REGNO_P (REGNO (iter_reg)))
4222 {
4223 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4224 lb_reg, end_label,
4225 lc_reg, iter_reg);
4226 seq_end = emit_insn (loop_init);
4227 }
4228 else if (!ENABLE_WA_LOAD_LCREGS && DPREG_P (iter_reg))
b03149e1 4229 {
97a988bc 4230 emit_insn (gen_movsi (lc_reg, iter_reg));
b03149e1
JZ
4231 loop_init = gen_lsetup_without_autoinit (lt_reg, start_label,
4232 lb_reg, end_label,
4233 lc_reg);
97a988bc 4234 seq_end = emit_insn (loop_init);
b03149e1 4235 }
97a988bc 4236 else if (scratchreg != NULL_RTX)
b03149e1 4237 {
e50e3081 4238 emit_insn (gen_movsi (scratchreg, scratch_init));
b03149e1
JZ
4239 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4240 lb_reg, end_label,
97a988bc
BS
4241 lc_reg, scratchreg);
4242 seq_end = emit_insn (loop_init);
e50e3081
BS
4243 if (scratch_init_insn != NULL_RTX)
4244 delete_insn (scratch_init_insn);
b03149e1
JZ
4245 }
4246 else
97a988bc
BS
4247 {
4248 rtx p0reg = gen_rtx_REG (SImode, REG_P0);
4249 rtx push = gen_frame_mem (SImode,
4250 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
4251 rtx pop = gen_frame_mem (SImode,
4252 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
4253 emit_insn (gen_movsi (push, p0reg));
e50e3081 4254 emit_insn (gen_movsi (p0reg, scratch_init));
97a988bc
BS
4255 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4256 lb_reg, end_label,
4257 lc_reg, p0reg);
4258 emit_insn (loop_init);
4259 seq_end = emit_insn (gen_movsi (p0reg, pop));
e50e3081
BS
4260 if (scratch_init_insn != NULL_RTX)
4261 delete_insn (scratch_init_insn);
97a988bc 4262 }
b03149e1
JZ
4263
4264 if (dump_file)
4265 {
4266 fprintf (dump_file, ";; replacing loop %d initializer with\n",
4267 loop->loop_no);
97a988bc 4268 print_rtl_single (dump_file, loop_init);
b03149e1
JZ
4269 fprintf (dump_file, ";; replacing loop %d terminator with\n",
4270 loop->loop_no);
4271 print_rtl_single (dump_file, loop->loop_end);
4272 }
4273
f4c59f4f
BS
4274 /* If the loop isn't entered at the top, also create a jump to the entry
4275 point. */
4276 if (!loop->incoming_src && loop->head != loop->incoming_dest)
4277 {
4278 rtx label = BB_HEAD (loop->incoming_dest);
4279 /* If we're jumping to the final basic block in the loop, and there's
4280 only one cheap instruction before the end (typically an increment of
4281 an induction variable), we can just emit a copy here instead of a
4282 jump. */
4283 if (loop->incoming_dest == loop->tail
4284 && next_real_insn (label) == last_insn
4285 && asm_noperands (last_insn) < 0
4286 && GET_CODE (PATTERN (last_insn)) == SET)
4287 {
4288 seq_end = emit_insn (copy_rtx (PATTERN (last_insn)));
4289 }
4290 else
8ff7f824
BS
4291 {
4292 emit_jump_insn (gen_jump (label));
4293 seq_end = emit_barrier ();
4294 }
f4c59f4f
BS
4295 }
4296
b03149e1
JZ
4297 seq = get_insns ();
4298 end_sequence ();
4299
ce27ef3d
BS
4300 if (loop->incoming_src)
4301 {
4302 rtx prev = BB_END (loop->incoming_src);
4303 if (VEC_length (edge, loop->incoming) > 1
4304 || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
4305 {
4306 gcc_assert (JUMP_P (prev));
4307 prev = PREV_INSN (prev);
4308 }
4309 emit_insn_after (seq, prev);
4310 }
4311 else
4312 {
4313 basic_block new_bb;
4314 edge e;
4315 edge_iterator ei;
f4c59f4f
BS
4316
4317#ifdef ENABLE_CHECKING
ce27ef3d
BS
4318 if (loop->head != loop->incoming_dest)
4319 {
f4c59f4f
BS
4320 /* We aren't entering the loop at the top. Since we've established
4321 that the loop is entered only at one point, this means there
4322 can't be fallthru edges into the head. Any such fallthru edges
4323 would become invalid when we insert the new block, so verify
4324 that this does not in fact happen. */
ce27ef3d 4325 FOR_EACH_EDGE (e, ei, loop->head->preds)
f4c59f4f 4326 gcc_assert (!(e->flags & EDGE_FALLTHRU));
ce27ef3d 4327 }
f4c59f4f 4328#endif
ce27ef3d
BS
4329
4330 emit_insn_before (seq, BB_HEAD (loop->head));
4331 seq = emit_label_before (gen_label_rtx (), seq);
b03149e1 4332
ce27ef3d
BS
4333 new_bb = create_basic_block (seq, seq_end, loop->head->prev_bb);
4334 FOR_EACH_EDGE (e, ei, loop->incoming)
4335 {
4336 if (!(e->flags & EDGE_FALLTHRU)
4337 || e->dest != loop->head)
4338 redirect_edge_and_branch_force (e, new_bb);
4339 else
4340 redirect_edge_succ (e, new_bb);
4341 }
8ff7f824 4342 e = make_edge (new_bb, loop->head, 0);
ce27ef3d 4343 }
307e7eab 4344
ce27ef3d 4345 delete_insn (loop->loop_end);
b03149e1
JZ
4346 /* Insert the loop end label before the last instruction of the loop. */
4347 emit_label_before (loop->end_label, loop->last_insn);
4348
4349 return;
4350
ce27ef3d 4351 bad_loop:
b03149e1
JZ
4352
4353 if (dump_file)
4354 fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
4355
e54273eb 4356 loop->bad = 1;
b03149e1
JZ
4357
4358 if (DPREG_P (loop->iter_reg))
4359 {
4360 /* If loop->iter_reg is a DREG or PREG, we can split it here
4361 without scratch register. */
f90b7a5a 4362 rtx insn, test;
b03149e1
JZ
4363
4364 emit_insn_before (gen_addsi3 (loop->iter_reg,
4365 loop->iter_reg,
4366 constm1_rtx),
4367 loop->loop_end);
4368
f90b7a5a
PB
4369 test = gen_rtx_NE (VOIDmode, loop->iter_reg, const0_rtx);
4370 insn = emit_jump_insn_before (gen_cbranchsi4 (test,
4371 loop->iter_reg, const0_rtx,
4372 loop->start_label),
b03149e1
JZ
4373 loop->loop_end);
4374
4375 JUMP_LABEL (insn) = loop->start_label;
4376 LABEL_NUSES (loop->start_label)++;
4377 delete_insn (loop->loop_end);
4378 }
4379}
4380
e54273eb
BS
4381/* Called from bfin_reorg_loops when a potential loop end is found. LOOP is
4382 a newly set up structure describing the loop, it is this function's
4383 responsibility to fill most of it. TAIL_BB and TAIL_INSN point to the
4384 loop_end insn and its enclosing basic block. */
4385
4386static void
4387bfin_discover_loop (loop_info loop, basic_block tail_bb, rtx tail_insn)
4388{
4389 unsigned dwork = 0;
4390 basic_block bb;
4391 VEC (basic_block,heap) *works = VEC_alloc (basic_block,heap,20);
4392
4393 loop->tail = tail_bb;
4394 loop->head = BRANCH_EDGE (tail_bb)->dest;
4395 loop->successor = FALLTHRU_EDGE (tail_bb)->dest;
e54273eb
BS
4396 loop->loop_end = tail_insn;
4397 loop->last_insn = NULL_RTX;
4398 loop->iter_reg = SET_DEST (XVECEXP (PATTERN (tail_insn), 0, 1));
4399 loop->depth = loop->length = 0;
4400 loop->visited = 0;
4401 loop->clobber_loop0 = loop->clobber_loop1 = 0;
4402 loop->outer = NULL;
4403 loop->loops = NULL;
ce27ef3d 4404 loop->incoming = VEC_alloc (edge, gc, 2);
e54273eb
BS
4405 loop->start_label = XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn), 0, 0)), 1), 0);
4406 loop->end_label = NULL_RTX;
4407 loop->bad = 0;
4408
4409 VEC_safe_push (basic_block, heap, works, loop->head);
4410
4411 while (VEC_iterate (basic_block, works, dwork++, bb))
4412 {
4413 edge e;
4414 edge_iterator ei;
4415 if (bb == EXIT_BLOCK_PTR)
4416 {
4417 /* We've reached the exit block. The loop must be bad. */
4418 if (dump_file)
4419 fprintf (dump_file,
4420 ";; Loop is bad - reached exit block while scanning\n");
4421 loop->bad = 1;
4422 break;
4423 }
4424
fcaa4ca4 4425 if (!bitmap_set_bit (loop->block_bitmap, bb->index))
e54273eb
BS
4426 continue;
4427
4428 /* We've not seen this block before. Add it to the loop's
4429 list and then add each successor to the work list. */
4430
4431 VEC_safe_push (basic_block, heap, loop->blocks, bb);
e54273eb
BS
4432
4433 if (bb != tail_bb)
4434 {
4435 FOR_EACH_EDGE (e, ei, bb->succs)
4436 {
4437 basic_block succ = EDGE_SUCC (bb, ei.index)->dest;
b18e284e 4438 if (!REGNO_REG_SET_P (df_get_live_in (succ),
e54273eb
BS
4439 REGNO (loop->iter_reg)))
4440 continue;
4441 if (!VEC_space (basic_block, works, 1))
4442 {
4443 if (dwork)
4444 {
4445 VEC_block_remove (basic_block, works, 0, dwork);
4446 dwork = 0;
4447 }
4448 else
4449 VEC_reserve (basic_block, heap, works, 1);
4450 }
4451 VEC_quick_push (basic_block, works, succ);
4452 }
4453 }
4454 }
4455
ce27ef3d 4456 /* Find the predecessor, and make sure nothing else jumps into this loop. */
e54273eb
BS
4457 if (!loop->bad)
4458 {
ce27ef3d 4459 int pass, retry;
ac47786e 4460 FOR_EACH_VEC_ELT (basic_block, loop->blocks, dwork, bb)
e54273eb 4461 {
ce27ef3d
BS
4462 edge e;
4463 edge_iterator ei;
4464 FOR_EACH_EDGE (e, ei, bb->preds)
4465 {
4466 basic_block pred = e->src;
4467
4468 if (!bfin_bb_in_loop (loop, pred))
4469 {
4470 if (dump_file)
4471 fprintf (dump_file, ";; Loop %d: incoming edge %d -> %d\n",
4472 loop->loop_no, pred->index,
4473 e->dest->index);
4474 VEC_safe_push (edge, gc, loop->incoming, e);
4475 }
4476 }
e54273eb
BS
4477 }
4478
ce27ef3d 4479 for (pass = 0, retry = 1; retry && pass < 2; pass++)
e54273eb 4480 {
ce27ef3d
BS
4481 edge e;
4482 edge_iterator ei;
4483 bool first = true;
4484 retry = 0;
4485
4486 FOR_EACH_EDGE (e, ei, loop->incoming)
4487 {
4488 if (first)
4489 {
4490 loop->incoming_src = e->src;
4491 loop->incoming_dest = e->dest;
4492 first = false;
4493 }
4494 else
4495 {
4496 if (e->dest != loop->incoming_dest)
4497 loop->incoming_dest = NULL;
4498 if (e->src != loop->incoming_src)
4499 loop->incoming_src = NULL;
4500 }
4501 if (loop->incoming_src == NULL && loop->incoming_dest == NULL)
4502 {
4503 if (pass == 0)
4504 {
4505 if (dump_file)
4506 fprintf (dump_file,
4507 ";; retrying loop %d with forwarder blocks\n",
4508 loop->loop_no);
4509 retry = 1;
4510 break;
4511 }
4512 loop->bad = 1;
4513 if (dump_file)
4514 fprintf (dump_file,
4515 ";; can't find suitable entry for loop %d\n",
4516 loop->loop_no);
4517 goto out;
4518 }
4519 }
4520 if (retry)
4521 {
4522 retry = 0;
4523 FOR_EACH_EDGE (e, ei, loop->incoming)
4524 {
4525 if (forwarder_block_p (e->src))
4526 {
4527 edge e2;
4528 edge_iterator ei2;
4529
4530 if (dump_file)
4531 fprintf (dump_file,
4532 ";; Adding forwarder block %d to loop %d and retrying\n",
4533 e->src->index, loop->loop_no);
4534 VEC_safe_push (basic_block, heap, loop->blocks, e->src);
4535 bitmap_set_bit (loop->block_bitmap, e->src->index);
4536 FOR_EACH_EDGE (e2, ei2, e->src->preds)
4537 VEC_safe_push (edge, gc, loop->incoming, e2);
4538 VEC_unordered_remove (edge, loop->incoming, ei.index);
4539 retry = 1;
4540 break;
4541 }
4542 }
f9e96751
BS
4543 if (!retry)
4544 {
4545 if (dump_file)
4546 fprintf (dump_file, ";; No forwarder blocks found\n");
4547 loop->bad = 1;
4548 }
ce27ef3d 4549 }
e54273eb
BS
4550 }
4551 }
4552
ce27ef3d 4553 out:
e54273eb
BS
4554 VEC_free (basic_block, heap, works);
4555}
4556
ce27ef3d
BS
4557/* Analyze the structure of the loops in the current function. Use STACK
4558 for bitmap allocations. Returns all the valid candidates for hardware
4559 loops found in this function. */
4560static loop_info
4561bfin_discover_loops (bitmap_obstack *stack, FILE *dump_file)
b03149e1 4562{
b03149e1
JZ
4563 loop_info loops = NULL;
4564 loop_info loop;
ce27ef3d
BS
4565 basic_block bb;
4566 bitmap tmp_bitmap;
b03149e1 4567 int nloops = 0;
e54273eb 4568
b03149e1
JZ
4569 /* Find all the possible loop tails. This means searching for every
4570 loop_end instruction. For each one found, create a loop_info
4571 structure and add the head block to the work list. */
4572 FOR_EACH_BB (bb)
4573 {
4574 rtx tail = BB_END (bb);
4575
4576 while (GET_CODE (tail) == NOTE)
4577 tail = PREV_INSN (tail);
4578
4579 bb->aux = NULL;
e54273eb 4580
f0f1c408 4581 if (INSN_P (tail) && recog_memoized (tail) == CODE_FOR_loop_end)
b03149e1 4582 {
4fc4d850 4583 rtx insn;
b03149e1
JZ
4584 /* A possible loop end */
4585
4fc4d850
BS
4586 /* There's a degenerate case we can handle - an empty loop consisting
4587 of only a back branch. Handle that by deleting the branch. */
4588 insn = BB_HEAD (BRANCH_EDGE (bb)->dest);
4589 if (next_real_insn (insn) == tail)
4590 {
4591 if (dump_file)
4592 {
4593 fprintf (dump_file, ";; degenerate loop ending at\n");
4594 print_rtl_single (dump_file, tail);
4595 }
4596 delete_insn_and_edges (tail);
4597 continue;
4598 }
4599
d3c176fc 4600 loop = XNEW (struct loop_info_d);
b03149e1
JZ
4601 loop->next = loops;
4602 loops = loop;
b03149e1 4603 loop->loop_no = nloops++;
e54273eb 4604 loop->blocks = VEC_alloc (basic_block, heap, 20);
ce27ef3d 4605 loop->block_bitmap = BITMAP_ALLOC (stack);
b03149e1
JZ
4606 bb->aux = loop;
4607
4608 if (dump_file)
4609 {
4610 fprintf (dump_file, ";; potential loop %d ending at\n",
4611 loop->loop_no);
4612 print_rtl_single (dump_file, tail);
4613 }
e54273eb
BS
4614
4615 bfin_discover_loop (loop, bb, tail);
b03149e1
JZ
4616 }
4617 }
4618
ce27ef3d 4619 tmp_bitmap = BITMAP_ALLOC (stack);
e54273eb
BS
4620 /* Compute loop nestings. */
4621 for (loop = loops; loop; loop = loop->next)
4622 {
4623 loop_info other;
4624 if (loop->bad)
4625 continue;
4626
4627 for (other = loop->next; other; other = other->next)
b03149e1 4628 {
e54273eb
BS
4629 if (other->bad)
4630 continue;
4631
4632 bitmap_and (tmp_bitmap, other->block_bitmap, loop->block_bitmap);
4633 if (bitmap_empty_p (tmp_bitmap))
4634 continue;
4635 if (bitmap_equal_p (tmp_bitmap, other->block_bitmap))
b03149e1 4636 {
e54273eb
BS
4637 other->outer = loop;
4638 VEC_safe_push (loop_info, heap, loop->loops, other);
4639 }
4640 else if (bitmap_equal_p (tmp_bitmap, loop->block_bitmap))
4641 {
4642 loop->outer = other;
4643 VEC_safe_push (loop_info, heap, other->loops, loop);
b03149e1 4644 }
b03149e1
JZ
4645 else
4646 {
ce27ef3d
BS
4647 if (dump_file)
4648 fprintf (dump_file,
4649 ";; can't find suitable nesting for loops %d and %d\n",
4650 loop->loop_no, other->loop_no);
e54273eb 4651 loop->bad = other->bad = 1;
b03149e1
JZ
4652 }
4653 }
4654 }
e54273eb 4655 BITMAP_FREE (tmp_bitmap);
b03149e1 4656
ce27ef3d
BS
4657 return loops;
4658}
4659
4660/* Free up the loop structures in LOOPS. */
4661static void
4662free_loops (loop_info loops)
4663{
4664 while (loops)
4665 {
4666 loop_info loop = loops;
4667 loops = loop->next;
4668 VEC_free (loop_info, heap, loop->loops);
4669 VEC_free (basic_block, heap, loop->blocks);
4670 BITMAP_FREE (loop->block_bitmap);
4671 XDELETE (loop);
4672 }
4673}
4674
4c425440 4675#define BB_AUX_INDEX(BB) ((intptr_t)(BB)->aux)
ce27ef3d
BS
4676
4677/* The taken-branch edge from the loop end can actually go forward. Since the
4678 Blackfin's LSETUP instruction requires that the loop end be after the loop
4679 start, try to reorder a loop's basic blocks when we find such a case. */
4680static void
4681bfin_reorder_loops (loop_info loops, FILE *dump_file)
4682{
4683 basic_block bb;
4684 loop_info loop;
4685
4686 FOR_EACH_BB (bb)
4687 bb->aux = NULL;
b18e284e 4688 cfg_layout_initialize (0);
ce27ef3d
BS
4689
4690 for (loop = loops; loop; loop = loop->next)
4691 {
4c425440 4692 intptr_t index;
ce27ef3d
BS
4693 basic_block bb;
4694 edge e;
4695 edge_iterator ei;
4696
4697 if (loop->bad)
4698 continue;
4699
4700 /* Recreate an index for basic blocks that represents their order. */
4701 for (bb = ENTRY_BLOCK_PTR->next_bb, index = 0;
4702 bb != EXIT_BLOCK_PTR;
4703 bb = bb->next_bb, index++)
4704 bb->aux = (PTR) index;
4705
4706 if (BB_AUX_INDEX (loop->head) < BB_AUX_INDEX (loop->tail))
4707 continue;
4708
4709 FOR_EACH_EDGE (e, ei, loop->head->succs)
4710 {
4711 if (bitmap_bit_p (loop->block_bitmap, e->dest->index)
4712 && BB_AUX_INDEX (e->dest) < BB_AUX_INDEX (loop->tail))
4713 {
4714 basic_block start_bb = e->dest;
4715 basic_block start_prev_bb = start_bb->prev_bb;
4716
4717 if (dump_file)
4718 fprintf (dump_file, ";; Moving block %d before block %d\n",
4719 loop->head->index, start_bb->index);
4720 loop->head->prev_bb->next_bb = loop->head->next_bb;
4721 loop->head->next_bb->prev_bb = loop->head->prev_bb;
4722
4723 loop->head->prev_bb = start_prev_bb;
4724 loop->head->next_bb = start_bb;
4725 start_prev_bb->next_bb = start_bb->prev_bb = loop->head;
4726 break;
4727 }
4728 }
4729 loops = loops->next;
4730 }
4731
4732 FOR_EACH_BB (bb)
4733 {
4734 if (bb->next_bb != EXIT_BLOCK_PTR)
4735 bb->aux = bb->next_bb;
4736 else
4737 bb->aux = NULL;
4738 }
4739 cfg_layout_finalize ();
b18e284e 4740 df_analyze ();
ce27ef3d
BS
4741}
4742
4743/* Run from machine_dependent_reorg, this pass looks for doloop_end insns
4744 and tries to rewrite the RTL of these loops so that proper Blackfin
4745 hardware loops are generated. */
4746
4747static void
4748bfin_reorg_loops (FILE *dump_file)
4749{
4750 loop_info loops = NULL;
4751 loop_info loop;
4752 basic_block bb;
4753 bitmap_obstack stack;
4754
4755 bitmap_obstack_initialize (&stack);
4756
4757 if (dump_file)
4758 fprintf (dump_file, ";; Find loops, first pass\n\n");
4759
4760 loops = bfin_discover_loops (&stack, dump_file);
4761
4762 if (dump_file)
4763 bfin_dump_loops (loops);
4764
4765 bfin_reorder_loops (loops, dump_file);
4766 free_loops (loops);
4767
4768 if (dump_file)
4769 fprintf (dump_file, ";; Find loops, second pass\n\n");
4770
4771 loops = bfin_discover_loops (&stack, dump_file);
b03149e1
JZ
4772 if (dump_file)
4773 {
4774 fprintf (dump_file, ";; All loops found:\n\n");
4775 bfin_dump_loops (loops);
4776 }
97a988bc 4777
b03149e1
JZ
4778 /* Now apply the optimizations. */
4779 for (loop = loops; loop; loop = loop->next)
4780 bfin_optimize_loop (loop);
4781
4782 if (dump_file)
4783 {
4784 fprintf (dump_file, ";; After hardware loops optimization:\n\n");
4785 bfin_dump_loops (loops);
4786 }
4787
ce27ef3d 4788 free_loops (loops);
b03149e1
JZ
4789
4790 if (dump_file)
4791 print_rtl (dump_file, get_insns ());
bbbc206e
BS
4792
4793 FOR_EACH_BB (bb)
4794 bb->aux = NULL;
97a988bc
BS
4795
4796 splitting_loops = 1;
4797 FOR_EACH_BB (bb)
4798 {
4799 rtx insn = BB_END (bb);
4800 if (!JUMP_P (insn))
4801 continue;
4802
4803 try_split (PATTERN (insn), insn, 1);
4804 }
4805 splitting_loops = 0;
b03149e1 4806}
bbbc206e
BS
4807\f
4808/* Possibly generate a SEQUENCE out of three insns found in SLOT.
4809 Returns true if we modified the insn chain, false otherwise. */
4810static bool
4811gen_one_bundle (rtx slot[3])
4812{
bbbc206e
BS
4813 gcc_assert (slot[1] != NULL_RTX);
4814
a524985e
BS
4815 /* Don't add extra NOPs if optimizing for size. */
4816 if (optimize_size
4817 && (slot[0] == NULL_RTX || slot[2] == NULL_RTX))
4818 return false;
4819
bbbc206e
BS
4820 /* Verify that we really can do the multi-issue. */
4821 if (slot[0])
4822 {
4823 rtx t = NEXT_INSN (slot[0]);
4824 while (t != slot[1])
4825 {
4826 if (GET_CODE (t) != NOTE
a38e7aa5 4827 || NOTE_KIND (t) != NOTE_INSN_DELETED)
bbbc206e
BS
4828 return false;
4829 t = NEXT_INSN (t);
4830 }
4831 }
4832 if (slot[2])
4833 {
4834 rtx t = NEXT_INSN (slot[1]);
4835 while (t != slot[2])
4836 {
4837 if (GET_CODE (t) != NOTE
a38e7aa5 4838 || NOTE_KIND (t) != NOTE_INSN_DELETED)
bbbc206e
BS
4839 return false;
4840 t = NEXT_INSN (t);
4841 }
4842 }
4843
4844 if (slot[0] == NULL_RTX)
b18e284e
BS
4845 {
4846 slot[0] = emit_insn_before (gen_mnop (), slot[1]);
4847 df_insn_rescan (slot[0]);
4848 }
bbbc206e 4849 if (slot[2] == NULL_RTX)
b18e284e
BS
4850 {
4851 slot[2] = emit_insn_after (gen_forced_nop (), slot[1]);
4852 df_insn_rescan (slot[2]);
4853 }
bbbc206e
BS
4854
4855 /* Avoid line number information being printed inside one bundle. */
4856 if (INSN_LOCATOR (slot[1])
4857 && INSN_LOCATOR (slot[1]) != INSN_LOCATOR (slot[0]))
4858 INSN_LOCATOR (slot[1]) = INSN_LOCATOR (slot[0]);
4859 if (INSN_LOCATOR (slot[2])
4860 && INSN_LOCATOR (slot[2]) != INSN_LOCATOR (slot[0]))
4861 INSN_LOCATOR (slot[2]) = INSN_LOCATOR (slot[0]);
4862
4863 /* Terminate them with "|| " instead of ";" in the output. */
4864 PUT_MODE (slot[0], SImode);
4865 PUT_MODE (slot[1], SImode);
b18e284e
BS
4866 /* Terminate the bundle, for the benefit of reorder_var_tracking_notes. */
4867 PUT_MODE (slot[2], QImode);
bbbc206e
BS
4868 return true;
4869}
4870
4871/* Go through all insns, and use the information generated during scheduling
4872 to generate SEQUENCEs to represent bundles of instructions issued
4873 simultaneously. */
4874
4875static void
4876bfin_gen_bundles (void)
4877{
4878 basic_block bb;
4879 FOR_EACH_BB (bb)
4880 {
4881 rtx insn, next;
4882 rtx slot[3];
4883 int n_filled = 0;
4884
4885 slot[0] = slot[1] = slot[2] = NULL_RTX;
4886 for (insn = BB_HEAD (bb);; insn = next)
4887 {
4888 int at_end;
c7cb1555
BS
4889 rtx delete_this = NULL_RTX;
4890
e5e44796 4891 if (NONDEBUG_INSN_P (insn))
bbbc206e 4892 {
c7cb1555
BS
4893 enum attr_type type = get_attr_type (insn);
4894
4895 if (type == TYPE_STALL)
4896 {
4897 gcc_assert (n_filled == 0);
4898 delete_this = insn;
4899 }
bbbc206e 4900 else
c7cb1555 4901 {
b3187e24 4902 if (type == TYPE_DSP32 || type == TYPE_DSP32SHIFTIMM)
c7cb1555
BS
4903 slot[0] = insn;
4904 else if (slot[1] == NULL_RTX)
4905 slot[1] = insn;
4906 else
4907 slot[2] = insn;
4908 n_filled++;
4909 }
bbbc206e
BS
4910 }
4911
4912 next = NEXT_INSN (insn);
4913 while (next && insn != BB_END (bb)
4914 && !(INSN_P (next)
4915 && GET_CODE (PATTERN (next)) != USE
4916 && GET_CODE (PATTERN (next)) != CLOBBER))
4917 {
4918 insn = next;
4919 next = NEXT_INSN (insn);
4920 }
b03149e1 4921
bbbc206e
BS
4922 /* BB_END can change due to emitting extra NOPs, so check here. */
4923 at_end = insn == BB_END (bb);
c7cb1555 4924 if (delete_this == NULL_RTX && (at_end || GET_MODE (next) == TImode))
bbbc206e
BS
4925 {
4926 if ((n_filled < 2
4927 || !gen_one_bundle (slot))
4928 && slot[0] != NULL_RTX)
4929 {
4930 rtx pat = PATTERN (slot[0]);
4931 if (GET_CODE (pat) == SET
4932 && GET_CODE (SET_SRC (pat)) == UNSPEC
4933 && XINT (SET_SRC (pat), 1) == UNSPEC_32BIT)
4934 {
4935 SET_SRC (pat) = XVECEXP (SET_SRC (pat), 0, 0);
4936 INSN_CODE (slot[0]) = -1;
b18e284e 4937 df_insn_rescan (slot[0]);
bbbc206e
BS
4938 }
4939 }
4940 n_filled = 0;
4941 slot[0] = slot[1] = slot[2] = NULL_RTX;
4942 }
c7cb1555
BS
4943 if (delete_this != NULL_RTX)
4944 delete_insn (delete_this);
bbbc206e
BS
4945 if (at_end)
4946 break;
4947 }
4948 }
4949}
b18e284e
BS
4950
4951/* Ensure that no var tracking notes are emitted in the middle of a
4952 three-instruction bundle. */
4953
4954static void
4955reorder_var_tracking_notes (void)
4956{
4957 basic_block bb;
4958 FOR_EACH_BB (bb)
4959 {
4960 rtx insn, next;
4961 rtx queue = NULL_RTX;
4962 bool in_bundle = false;
4963
4964 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4965 {
4966 next = NEXT_INSN (insn);
4967
4968 if (INSN_P (insn))
4969 {
4970 /* Emit queued up notes at the last instruction of a bundle. */
4971 if (GET_MODE (insn) == QImode)
4972 {
4973 while (queue)
4974 {
4975 rtx next_queue = PREV_INSN (queue);
4976 PREV_INSN (NEXT_INSN (insn)) = queue;
4977 NEXT_INSN (queue) = NEXT_INSN (insn);
4978 NEXT_INSN (insn) = queue;
4979 PREV_INSN (queue) = insn;
4980 queue = next_queue;
4981 }
4982 in_bundle = false;
4983 }
4984 else if (GET_MODE (insn) == SImode)
4985 in_bundle = true;
4986 }
4987 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4988 {
4989 if (in_bundle)
4990 {
4991 rtx prev = PREV_INSN (insn);
4992 PREV_INSN (next) = prev;
4993 NEXT_INSN (prev) = next;
4994
4995 PREV_INSN (insn) = queue;
4996 queue = insn;
4997 }
4998 }
4999 }
5000 }
5001}
0d4a78eb 5002\f
22fb24d5
BS
5003/* On some silicon revisions, functions shorter than a certain number of cycles
5004 can cause unpredictable behaviour. Work around this by adding NOPs as
5005 needed. */
5006static void
5007workaround_rts_anomaly (void)
5008{
5009 rtx insn, first_insn = NULL_RTX;
5010 int cycles = 4;
5011
5012 if (! ENABLE_WA_RETS)
5013 return;
5014
5015 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5016 {
5017 rtx pat;
5018
5019 if (BARRIER_P (insn))
5020 return;
5021
5022 if (NOTE_P (insn) || LABEL_P (insn))
5023 continue;
5024
5025 if (first_insn == NULL_RTX)
5026 first_insn = insn;
5027 pat = PATTERN (insn);
5028 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5029 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5030 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5031 continue;
5032
5033 if (CALL_P (insn))
5034 return;
5035
5036 if (JUMP_P (insn))
5037 {
5038 if (recog_memoized (insn) == CODE_FOR_return_internal)
5039 break;
5040
5041 /* Nothing to worry about for direct jumps. */
5042 if (!any_condjump_p (insn))
5043 return;
5044 if (cycles <= 1)
5045 return;
5046 cycles--;
5047 }
5048 else if (INSN_P (insn))
5049 {
5050 rtx pat = PATTERN (insn);
5051 int this_cycles = 1;
5052
5053 if (GET_CODE (pat) == PARALLEL)
5054 {
5055 if (push_multiple_operation (pat, VOIDmode)
5056 || pop_multiple_operation (pat, VOIDmode))
5057 this_cycles = n_regs_to_save;
5058 }
5059 else
5060 {
d3c176fc
JR
5061 int icode = recog_memoized (insn);
5062
22fb24d5
BS
5063 if (icode == CODE_FOR_link)
5064 this_cycles = 4;
5065 else if (icode == CODE_FOR_unlink)
5066 this_cycles = 3;
5067 else if (icode == CODE_FOR_mulsi3)
5068 this_cycles = 5;
5069 }
5070 if (this_cycles >= cycles)
5071 return;
5072
5073 cycles -= this_cycles;
5074 }
5075 }
5076 while (cycles > 0)
5077 {
5078 emit_insn_before (gen_nop (), first_insn);
5079 cycles--;
5080 }
5081}
5082
bbbc206e
BS
5083/* Return an insn type for INSN that can be used by the caller for anomaly
5084 workarounds. This differs from plain get_attr_type in that it handles
5085 SEQUENCEs. */
5086
5087static enum attr_type
5088type_for_anomaly (rtx insn)
5089{
5090 rtx pat = PATTERN (insn);
5091 if (GET_CODE (pat) == SEQUENCE)
5092 {
5093 enum attr_type t;
5094 t = get_attr_type (XVECEXP (pat, 0, 1));
5095 if (t == TYPE_MCLD)
5096 return t;
5097 t = get_attr_type (XVECEXP (pat, 0, 2));
5098 if (t == TYPE_MCLD)
5099 return t;
5100 return TYPE_MCST;
5101 }
5102 else
5103 return get_attr_type (insn);
5104}
5105
8472b255
BS
5106/* Return true iff the address found in MEM is based on the register
5107 NP_REG and optionally has a positive offset. */
bbbc206e 5108static bool
8472b255 5109harmless_null_pointer_p (rtx mem, int np_reg)
bbbc206e 5110{
8472b255
BS
5111 mem = XEXP (mem, 0);
5112 if (GET_CODE (mem) == POST_INC || GET_CODE (mem) == POST_DEC)
5113 mem = XEXP (mem, 0);
d3c176fc 5114 if (REG_P (mem) && (int) REGNO (mem) == np_reg)
8472b255
BS
5115 return true;
5116 if (GET_CODE (mem) == PLUS
d3c176fc 5117 && REG_P (XEXP (mem, 0)) && (int) REGNO (XEXP (mem, 0)) == np_reg)
bbbc206e 5118 {
8472b255
BS
5119 mem = XEXP (mem, 1);
5120 if (GET_CODE (mem) == CONST_INT && INTVAL (mem) > 0)
bbbc206e 5121 return true;
bbbc206e 5122 }
8472b255
BS
5123 return false;
5124}
5125
5126/* Return nonzero if INSN contains any loads that may trap. */
5127
5128static bool
5129trapping_loads_p (rtx insn, int np_reg, bool after_np_branch)
5130{
8472b255
BS
5131 rtx mem = SET_SRC (single_set (insn));
5132
5133 if (!after_np_branch)
5134 np_reg = -1;
5135 return ((np_reg == -1 || !harmless_null_pointer_p (mem, np_reg))
5136 && may_trap_p (mem));
bbbc206e
BS
5137}
5138
44017a45
BS
5139/* Return INSN if it is of TYPE_MCLD. Alternatively, if INSN is the start of
5140 a three-insn bundle, see if one of them is a load and return that if so.
5141 Return NULL_RTX if the insn does not contain loads. */
5142static rtx
5143find_load (rtx insn)
5144{
e5e44796
JZ
5145 if (!NONDEBUG_INSN_P (insn))
5146 return NULL_RTX;
44017a45
BS
5147 if (get_attr_type (insn) == TYPE_MCLD)
5148 return insn;
5149 if (GET_MODE (insn) != SImode)
5150 return NULL_RTX;
5151 do {
5152 insn = NEXT_INSN (insn);
5153 if ((GET_MODE (insn) == SImode || GET_MODE (insn) == QImode)
5154 && get_attr_type (insn) == TYPE_MCLD)
5155 return insn;
5156 } while (GET_MODE (insn) != QImode);
5157 return NULL_RTX;
5158}
5159
bf85bc3d
BS
5160/* Determine whether PAT is an indirect call pattern. */
5161static bool
5162indirect_call_p (rtx pat)
5163{
5164 if (GET_CODE (pat) == PARALLEL)
5165 pat = XVECEXP (pat, 0, 0);
5166 if (GET_CODE (pat) == SET)
5167 pat = SET_SRC (pat);
5168 gcc_assert (GET_CODE (pat) == CALL);
5169 pat = XEXP (pat, 0);
5170 gcc_assert (GET_CODE (pat) == MEM);
5171 pat = XEXP (pat, 0);
5172
5173 return REG_P (pat);
5174}
5175
8472b255
BS
5176/* During workaround_speculation, track whether we're in the shadow of a
5177 conditional branch that tests a P register for NULL. If so, we can omit
5178 emitting NOPs if we see a load from that P register, since a speculative
5179 access at address 0 isn't a problem, and the load is executed in all other
5180 cases anyway.
5181 Global for communication with note_np_check_stores through note_stores.
5182 */
5183int np_check_regno = -1;
5184bool np_after_branch = false;
5185
5186/* Subroutine of workaround_speculation, called through note_stores. */
5187static void
d3c176fc
JR
5188note_np_check_stores (rtx x, const_rtx pat ATTRIBUTE_UNUSED,
5189 void *data ATTRIBUTE_UNUSED)
8472b255 5190{
d3c176fc 5191 if (REG_P (x) && (REGNO (x) == REG_CC || (int) REGNO (x) == np_check_regno))
8472b255
BS
5192 np_check_regno = -1;
5193}
5194
0d4a78eb 5195static void
22fb24d5 5196workaround_speculation (void)
0d4a78eb 5197{
44017a45
BS
5198 rtx insn, next;
5199 rtx last_condjump = NULL_RTX;
0d4a78eb 5200 int cycles_since_jump = INT_MAX;
90cbba02 5201 int delay_added = 0;
0d4a78eb 5202
bf85bc3d
BS
5203 if (! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS
5204 && ! ENABLE_WA_INDIRECT_CALLS)
0d4a78eb
BS
5205 return;
5206
3fb192d2
BS
5207 /* First pass: find predicted-false branches; if something after them
5208 needs nops, insert them or change the branch to predict true. */
44017a45 5209 for (insn = get_insns (); insn; insn = next)
0d4a78eb
BS
5210 {
5211 rtx pat;
90cbba02 5212 int delay_needed = 0;
0d4a78eb 5213
44017a45
BS
5214 next = find_next_insn_start (insn);
5215
8472b255 5216 if (NOTE_P (insn) || BARRIER_P (insn))
0d4a78eb
BS
5217 continue;
5218
8472b255
BS
5219 if (LABEL_P (insn))
5220 {
5221 np_check_regno = -1;
5222 continue;
5223 }
5224
0d4a78eb
BS
5225 pat = PATTERN (insn);
5226 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
8472b255 5227 || GET_CODE (pat) == ADDR_VEC || GET_CODE (pat) == ADDR_DIFF_VEC)
0d4a78eb 5228 continue;
8472b255
BS
5229
5230 if (GET_CODE (pat) == ASM_INPUT || asm_noperands (pat) >= 0)
5231 {
5232 np_check_regno = -1;
5233 continue;
5234 }
0d4a78eb
BS
5235
5236 if (JUMP_P (insn))
5237 {
8472b255
BS
5238 /* Is this a condjump based on a null pointer comparison we saw
5239 earlier? */
5240 if (np_check_regno != -1
5241 && recog_memoized (insn) == CODE_FOR_cbranchbi4)
5242 {
5243 rtx op = XEXP (SET_SRC (PATTERN (insn)), 0);
5244 gcc_assert (GET_CODE (op) == EQ || GET_CODE (op) == NE);
5245 if (GET_CODE (op) == NE)
5246 np_after_branch = true;
5247 }
0d4a78eb
BS
5248 if (any_condjump_p (insn)
5249 && ! cbranch_predicted_taken_p (insn))
5250 {
5251 last_condjump = insn;
90cbba02 5252 delay_added = 0;
0d4a78eb
BS
5253 cycles_since_jump = 0;
5254 }
5255 else
5256 cycles_since_jump = INT_MAX;
5257 }
bf85bc3d
BS
5258 else if (CALL_P (insn))
5259 {
8472b255 5260 np_check_regno = -1;
bf85bc3d
BS
5261 if (cycles_since_jump < INT_MAX)
5262 cycles_since_jump++;
5263 if (indirect_call_p (pat) && ENABLE_WA_INDIRECT_CALLS)
5264 {
5265 delay_needed = 3;
5266 }
5267 }
e5e44796 5268 else if (NONDEBUG_INSN_P (insn))
0d4a78eb 5269 {
44017a45 5270 rtx load_insn = find_load (insn);
bbbc206e 5271 enum attr_type type = type_for_anomaly (insn);
90cbba02 5272
0d4a78eb
BS
5273 if (cycles_since_jump < INT_MAX)
5274 cycles_since_jump++;
5275
8472b255
BS
5276 /* Detect a comparison of a P register with zero. If we later
5277 see a condjump based on it, we have found a null pointer
5278 check. */
5279 if (recog_memoized (insn) == CODE_FOR_compare_eq)
5280 {
5281 rtx src = SET_SRC (PATTERN (insn));
5282 if (REG_P (XEXP (src, 0))
5283 && P_REGNO_P (REGNO (XEXP (src, 0)))
5284 && XEXP (src, 1) == const0_rtx)
5285 {
5286 np_check_regno = REGNO (XEXP (src, 0));
5287 np_after_branch = false;
5288 }
5289 else
5290 np_check_regno = -1;
5291 }
5292
ea2382be 5293 if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
3fb192d2 5294 {
8472b255
BS
5295 if (trapping_loads_p (load_insn, np_check_regno,
5296 np_after_branch))
90cbba02 5297 delay_needed = 4;
3fb192d2 5298 }
ea2382be 5299 else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
90cbba02 5300 delay_needed = 3;
8472b255
BS
5301
5302 /* See if we need to forget about a null pointer comparison
5303 we found earlier. */
5304 if (recog_memoized (insn) != CODE_FOR_compare_eq)
5305 {
5306 note_stores (PATTERN (insn), note_np_check_stores, NULL);
5307 if (np_check_regno != -1)
5308 {
5309 if (find_regno_note (insn, REG_INC, np_check_regno))
5310 np_check_regno = -1;
5311 }
5312 }
5313
90cbba02 5314 }
3fb192d2 5315
90cbba02
BS
5316 if (delay_needed > cycles_since_jump
5317 && (delay_needed - cycles_since_jump) > delay_added)
5318 {
5319 rtx pat1;
5320 int num_clobbers;
5321 rtx *op = recog_data.operand;
0d4a78eb 5322
90cbba02 5323 delay_needed -= cycles_since_jump;
3fb192d2 5324
90cbba02
BS
5325 extract_insn (last_condjump);
5326 if (optimize_size)
5327 {
5328 pat1 = gen_cbranch_predicted_taken (op[0], op[1], op[2],
5329 op[3]);
5330 cycles_since_jump = INT_MAX;
5331 }
5332 else
5333 {
5334 /* Do not adjust cycles_since_jump in this case, so that
5335 we'll increase the number of NOPs for a subsequent insn
5336 if necessary. */
5337 pat1 = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
5338 GEN_INT (delay_needed));
5339 delay_added = delay_needed;
3fb192d2 5340 }
90cbba02
BS
5341 PATTERN (last_condjump) = pat1;
5342 INSN_CODE (last_condjump) = recog (pat1, insn, &num_clobbers);
5343 }
5344 if (CALL_P (insn))
5345 {
5346 cycles_since_jump = INT_MAX;
5347 delay_added = 0;
3fb192d2
BS
5348 }
5349 }
90cbba02 5350
3fb192d2
BS
5351 /* Second pass: for predicted-true branches, see if anything at the
5352 branch destination needs extra nops. */
3fb192d2
BS
5353 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5354 {
22fb24d5 5355 int cycles_since_jump;
3fb192d2
BS
5356 if (JUMP_P (insn)
5357 && any_condjump_p (insn)
5358 && (INSN_CODE (insn) == CODE_FOR_cbranch_predicted_taken
5359 || cbranch_predicted_taken_p (insn)))
5360 {
5361 rtx target = JUMP_LABEL (insn);
5362 rtx label = target;
90cbba02
BS
5363 rtx next_tgt;
5364
3fb192d2 5365 cycles_since_jump = 0;
90cbba02 5366 for (; target && cycles_since_jump < 3; target = next_tgt)
3fb192d2
BS
5367 {
5368 rtx pat;
5369
90cbba02
BS
5370 next_tgt = find_next_insn_start (target);
5371
3fb192d2
BS
5372 if (NOTE_P (target) || BARRIER_P (target) || LABEL_P (target))
5373 continue;
5374
5375 pat = PATTERN (target);
5376 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5377 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5378 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5379 continue;
5380
e5e44796 5381 if (NONDEBUG_INSN_P (target))
3fb192d2 5382 {
90cbba02 5383 rtx load_insn = find_load (target);
bbbc206e 5384 enum attr_type type = type_for_anomaly (target);
3fb192d2
BS
5385 int delay_needed = 0;
5386 if (cycles_since_jump < INT_MAX)
5387 cycles_since_jump++;
5388
90cbba02
BS
5389 if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5390 {
8472b255 5391 if (trapping_loads_p (load_insn, -1, false))
90cbba02
BS
5392 delay_needed = 2;
5393 }
5394 else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
3fb192d2
BS
5395 delay_needed = 2;
5396
5397 if (delay_needed > cycles_since_jump)
5398 {
5399 rtx prev = prev_real_insn (label);
5400 delay_needed -= cycles_since_jump;
5401 if (dump_file)
5402 fprintf (dump_file, "Adding %d nops after %d\n",
5403 delay_needed, INSN_UID (label));
5404 if (JUMP_P (prev)
5405 && INSN_CODE (prev) == CODE_FOR_cbranch_with_nops)
5406 {
5407 rtx x;
5408 HOST_WIDE_INT v;
5409
5410 if (dump_file)
5411 fprintf (dump_file,
5412 "Reducing nops on insn %d.\n",
5413 INSN_UID (prev));
5414 x = PATTERN (prev);
5415 x = XVECEXP (x, 0, 1);
5416 v = INTVAL (XVECEXP (x, 0, 0)) - delay_needed;
5417 XVECEXP (x, 0, 0) = GEN_INT (v);
5418 }
5419 while (delay_needed-- > 0)
5420 emit_insn_after (gen_nop (), label);
5421 break;
5422 }
5423 }
0d4a78eb
BS
5424 }
5425 }
5426 }
22fb24d5
BS
5427}
5428
c7cb1555
BS
5429/* Called just before the final scheduling pass. If we need to insert NOPs
5430 later on to work around speculative loads, insert special placeholder
5431 insns that cause loads to be delayed for as many cycles as necessary
5432 (and possible). This reduces the number of NOPs we need to add.
5433 The dummy insns we generate are later removed by bfin_gen_bundles. */
5434static void
5435add_sched_insns_for_speculation (void)
5436{
5437 rtx insn;
5438
5439 if (! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS
5440 && ! ENABLE_WA_INDIRECT_CALLS)
5441 return;
5442
5443 /* First pass: find predicted-false branches; if something after them
5444 needs nops, insert them or change the branch to predict true. */
5445 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5446 {
5447 rtx pat;
5448
5449 if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
5450 continue;
5451
5452 pat = PATTERN (insn);
5453 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5454 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5455 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5456 continue;
5457
5458 if (JUMP_P (insn))
5459 {
5460 if (any_condjump_p (insn)
5461 && !cbranch_predicted_taken_p (insn))
5462 {
5463 rtx n = next_real_insn (insn);
5464 emit_insn_before (gen_stall (GEN_INT (3)), n);
5465 }
5466 }
5467 }
5468
5469 /* Second pass: for predicted-true branches, see if anything at the
5470 branch destination needs extra nops. */
5471 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5472 {
5473 if (JUMP_P (insn)
5474 && any_condjump_p (insn)
5475 && (cbranch_predicted_taken_p (insn)))
5476 {
5477 rtx target = JUMP_LABEL (insn);
5478 rtx next = next_real_insn (target);
5479
5480 if (GET_CODE (PATTERN (next)) == UNSPEC_VOLATILE
5481 && get_attr_type (next) == TYPE_STALL)
5482 continue;
5483 emit_insn_before (gen_stall (GEN_INT (1)), next);
5484 }
5485 }
5486}
5487
22fb24d5
BS
5488/* We use the machine specific reorg pass for emitting CSYNC instructions
5489 after conditional branches as needed.
5490
5491 The Blackfin is unusual in that a code sequence like
5492 if cc jump label
5493 r0 = (p0)
5494 may speculatively perform the load even if the condition isn't true. This
5495 happens for a branch that is predicted not taken, because the pipeline
5496 isn't flushed or stalled, so the early stages of the following instructions,
5497 which perform the memory reference, are allowed to execute before the
5498 jump condition is evaluated.
5499 Therefore, we must insert additional instructions in all places where this
5500 could lead to incorrect behavior. The manual recommends CSYNC, while
5501 VDSP seems to use NOPs (even though its corresponding compiler option is
5502 named CSYNC).
5503
5504 When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
5505 When optimizing for size, we turn the branch into a predicted taken one.
5506 This may be slower due to mispredicts, but saves code size. */
5507
5508static void
5509bfin_reorg (void)
5510{
5511 /* We are freeing block_for_insn in the toplev to keep compatibility
5512 with old MDEP_REORGS that are not CFG based. Recompute it now. */
5513 compute_bb_for_insn ();
5514
5515 if (bfin_flag_schedule_insns2)
5516 {
5517 splitting_for_sched = 1;
5518 split_all_insns ();
5519 splitting_for_sched = 0;
5520
c7cb1555
BS
5521 add_sched_insns_for_speculation ();
5522
22fb24d5 5523 timevar_push (TV_SCHED2);
6cca15ea
BS
5524 if (flag_selective_scheduling2
5525 && !maybe_skip_selective_scheduling ())
5526 run_selective_scheduling ();
5527 else
5528 schedule_insns ();
22fb24d5
BS
5529 timevar_pop (TV_SCHED2);
5530
5531 /* Examine the schedule and insert nops as necessary for 64-bit parallel
5532 instructions. */
5533 bfin_gen_bundles ();
5534 }
5535
5536 df_analyze ();
5537
5538 /* Doloop optimization */
5539 if (cfun->machine->has_hardware_loops)
5540 bfin_reorg_loops (dump_file);
5541
5542 workaround_speculation ();
bbbc206e
BS
5543
5544 if (bfin_flag_var_tracking)
5545 {
5546 timevar_push (TV_VAR_TRACKING);
5547 variable_tracking_main ();
b18e284e 5548 reorder_var_tracking_notes ();
bbbc206e
BS
5549 timevar_pop (TV_VAR_TRACKING);
5550 }
22fb24d5 5551
0d475361 5552 df_finish_pass (false);
22fb24d5
BS
5553
5554 workaround_rts_anomaly ();
0d4a78eb
BS
5555}
5556\f
5557/* Handle interrupt_handler, exception_handler and nmi_handler function
5558 attributes; arguments as in struct attribute_spec.handler. */
5559
5560static tree
5561handle_int_attribute (tree *node, tree name,
5562 tree args ATTRIBUTE_UNUSED,
5563 int flags ATTRIBUTE_UNUSED,
5564 bool *no_add_attrs)
5565{
5566 tree x = *node;
5567 if (TREE_CODE (x) == FUNCTION_DECL)
5568 x = TREE_TYPE (x);
5569
5570 if (TREE_CODE (x) != FUNCTION_TYPE)
5571 {
29d08eba
JM
5572 warning (OPT_Wattributes, "%qE attribute only applies to functions",
5573 name);
0d4a78eb
BS
5574 *no_add_attrs = true;
5575 }
5576 else if (funkind (x) != SUBROUTINE)
5577 error ("multiple function type attributes specified");
5578
5579 return NULL_TREE;
5580}
5581
5582/* Return 0 if the attributes for two types are incompatible, 1 if they
5583 are compatible, and 2 if they are nearly compatible (which causes a
5584 warning to be generated). */
5585
5586static int
3101faab 5587bfin_comp_type_attributes (const_tree type1, const_tree type2)
0d4a78eb
BS
5588{
5589 e_funkind kind1, kind2;
5590
5591 if (TREE_CODE (type1) != FUNCTION_TYPE)
5592 return 1;
5593
5594 kind1 = funkind (type1);
5595 kind2 = funkind (type2);
5596
5597 if (kind1 != kind2)
5598 return 0;
5599
5600 /* Check for mismatched modifiers */
5601 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
5602 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
5603 return 0;
5604
5605 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
5606 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
5607 return 0;
5608
5609 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
5610 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
5611 return 0;
5612
6d459e2b
BS
5613 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
5614 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
5615 return 0;
5616
0d4a78eb
BS
5617 return 1;
5618}
5619
6d459e2b
BS
5620/* Handle a "longcall" or "shortcall" attribute; arguments as in
5621 struct attribute_spec.handler. */
5622
5623static tree
5624bfin_handle_longcall_attribute (tree *node, tree name,
5625 tree args ATTRIBUTE_UNUSED,
5626 int flags ATTRIBUTE_UNUSED,
5627 bool *no_add_attrs)
5628{
5629 if (TREE_CODE (*node) != FUNCTION_TYPE
5630 && TREE_CODE (*node) != FIELD_DECL
5631 && TREE_CODE (*node) != TYPE_DECL)
5632 {
29d08eba
JM
5633 warning (OPT_Wattributes, "%qE attribute only applies to functions",
5634 name);
6d459e2b
BS
5635 *no_add_attrs = true;
5636 }
5637
5638 if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
5639 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
5640 || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
5641 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
5642 {
5643 warning (OPT_Wattributes,
d8a07487 5644 "can%'t apply both longcall and shortcall attributes to the same function");
6d459e2b
BS
5645 *no_add_attrs = true;
5646 }
5647
5648 return NULL_TREE;
5649}
5650
4af797b5
JZ
5651/* Handle a "l1_text" attribute; arguments as in
5652 struct attribute_spec.handler. */
5653
5654static tree
5655bfin_handle_l1_text_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5656 int ARG_UNUSED (flags), bool *no_add_attrs)
5657{
5658 tree decl = *node;
5659
5660 if (TREE_CODE (decl) != FUNCTION_DECL)
5661 {
29d08eba
JM
5662 error ("%qE attribute only applies to functions",
5663 name);
4af797b5
JZ
5664 *no_add_attrs = true;
5665 }
5666
5667 /* The decl may have already been given a section attribute
5668 from a previous declaration. Ensure they match. */
5669 else if (DECL_SECTION_NAME (decl) != NULL_TREE
5670 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5671 ".l1.text") != 0)
5672 {
5673 error ("section of %q+D conflicts with previous declaration",
5674 decl);
5675 *no_add_attrs = true;
5676 }
5677 else
5678 DECL_SECTION_NAME (decl) = build_string (9, ".l1.text");
5679
5680 return NULL_TREE;
5681}
5682
5683/* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
5684 arguments as in struct attribute_spec.handler. */
5685
5686static tree
5687bfin_handle_l1_data_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5688 int ARG_UNUSED (flags), bool *no_add_attrs)
5689{
5690 tree decl = *node;
5691
5692 if (TREE_CODE (decl) != VAR_DECL)
5693 {
29d08eba
JM
5694 error ("%qE attribute only applies to variables",
5695 name);
4af797b5
JZ
5696 *no_add_attrs = true;
5697 }
5698 else if (current_function_decl != NULL_TREE
5699 && !TREE_STATIC (decl))
5700 {
29d08eba
JM
5701 error ("%qE attribute cannot be specified for local variables",
5702 name);
4af797b5
JZ
5703 *no_add_attrs = true;
5704 }
5705 else
5706 {
5707 const char *section_name;
5708
5709 if (strcmp (IDENTIFIER_POINTER (name), "l1_data") == 0)
5710 section_name = ".l1.data";
5711 else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_A") == 0)
5712 section_name = ".l1.data.A";
5713 else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_B") == 0)
5714 section_name = ".l1.data.B";
5715 else
5716 gcc_unreachable ();
5717
5718 /* The decl may have already been given a section attribute
5719 from a previous declaration. Ensure they match. */
5720 if (DECL_SECTION_NAME (decl) != NULL_TREE
5721 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5722 section_name) != 0)
5723 {
5724 error ("section of %q+D conflicts with previous declaration",
5725 decl);
5726 *no_add_attrs = true;
5727 }
5728 else
5729 DECL_SECTION_NAME (decl)
5730 = build_string (strlen (section_name) + 1, section_name);
5731 }
5732
5733 return NULL_TREE;
5734}
5735
db689ed6
BS
5736/* Handle a "l2" attribute; arguments as in struct attribute_spec.handler. */
5737
5738static tree
5739bfin_handle_l2_attribute (tree *node, tree ARG_UNUSED (name),
5740 tree ARG_UNUSED (args), int ARG_UNUSED (flags),
5741 bool *no_add_attrs)
5742{
5743 tree decl = *node;
5744
5745 if (TREE_CODE (decl) == FUNCTION_DECL)
5746 {
5747 if (DECL_SECTION_NAME (decl) != NULL_TREE
5748 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5749 ".l2.text") != 0)
5750 {
5751 error ("section of %q+D conflicts with previous declaration",
5752 decl);
5753 *no_add_attrs = true;
5754 }
5755 else
5756 DECL_SECTION_NAME (decl) = build_string (9, ".l2.text");
5757 }
5758 else if (TREE_CODE (decl) == VAR_DECL)
5759 {
5760 if (DECL_SECTION_NAME (decl) != NULL_TREE
5761 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5762 ".l2.data") != 0)
5763 {
5764 error ("section of %q+D conflicts with previous declaration",
5765 decl);
5766 *no_add_attrs = true;
5767 }
5768 else
5769 DECL_SECTION_NAME (decl) = build_string (9, ".l2.data");
5770 }
5771
5772 return NULL_TREE;
5773}
5774
0d4a78eb 5775/* Table of valid machine attributes. */
6bc7bc14 5776static const struct attribute_spec bfin_attribute_table[] =
0d4a78eb 5777{
62d784f7
KT
5778 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
5779 affects_type_identity } */
5780 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute,
5781 false },
5782 { "exception_handler", 0, 0, false, true, true, handle_int_attribute,
5783 false },
5784 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute, false },
5785 { "nesting", 0, 0, false, true, true, NULL, false },
5786 { "kspisusp", 0, 0, false, true, true, NULL, false },
5787 { "saveall", 0, 0, false, true, true, NULL, false },
5788 { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute,
5789 false },
5790 { "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute,
5791 false },
5792 { "l1_text", 0, 0, true, false, false, bfin_handle_l1_text_attribute,
5793 false },
5794 { "l1_data", 0, 0, true, false, false, bfin_handle_l1_data_attribute,
5795 false },
5796 { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute,
5797 false },
5798 { "l1_data_B", 0, 0, true, false, false, bfin_handle_l1_data_attribute,
5799 false },
5800 { "l2", 0, 0, true, false, false, bfin_handle_l2_attribute, false },
5801 { NULL, 0, 0, false, false, false, NULL, false }
0d4a78eb
BS
5802};
5803\f
6614f9f5
BS
5804/* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to
5805 tell the assembler to generate pointers to function descriptors in
5806 some cases. */
5807
5808static bool
5809bfin_assemble_integer (rtx value, unsigned int size, int aligned_p)
5810{
5811 if (TARGET_FDPIC && size == UNITS_PER_WORD)
5812 {
5813 if (GET_CODE (value) == SYMBOL_REF
5814 && SYMBOL_REF_FUNCTION_P (value))
5815 {
5816 fputs ("\t.picptr\tfuncdesc(", asm_out_file);
5817 output_addr_const (asm_out_file, value);
5818 fputs (")\n", asm_out_file);
5819 return true;
5820 }
5821 if (!aligned_p)
5822 {
5823 /* We've set the unaligned SI op to NULL, so we always have to
5824 handle the unaligned case here. */
5825 assemble_integer_with_op ("\t.4byte\t", value);
5826 return true;
5827 }
5828 }
5829 return default_assemble_integer (value, size, aligned_p);
5830}
5831\f
0d4a78eb
BS
5832/* Output the assembler code for a thunk function. THUNK_DECL is the
5833 declaration for the thunk function itself, FUNCTION is the decl for
5834 the target function. DELTA is an immediate constant offset to be
5835 added to THIS. If VCALL_OFFSET is nonzero, the word at
5836 *(*this + vcall_offset) should be added to THIS. */
5837
5838static void
5839bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
5840 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
5841 HOST_WIDE_INT vcall_offset, tree function)
5842{
5843 rtx xops[3];
5844 /* The this parameter is passed as the first argument. */
0a2aaacc 5845 rtx this_rtx = gen_rtx_REG (Pmode, REG_R0);
0d4a78eb
BS
5846
5847 /* Adjust the this parameter by a fixed constant. */
5848 if (delta)
5849 {
0a2aaacc 5850 xops[1] = this_rtx;
0d4a78eb
BS
5851 if (delta >= -64 && delta <= 63)
5852 {
5853 xops[0] = GEN_INT (delta);
5854 output_asm_insn ("%1 += %0;", xops);
5855 }
5856 else if (delta >= -128 && delta < -64)
5857 {
5858 xops[0] = GEN_INT (delta + 64);
5859 output_asm_insn ("%1 += -64; %1 += %0;", xops);
5860 }
5861 else if (delta > 63 && delta <= 126)
5862 {
5863 xops[0] = GEN_INT (delta - 63);
5864 output_asm_insn ("%1 += 63; %1 += %0;", xops);
5865 }
5866 else
5867 {
5868 xops[0] = GEN_INT (delta);
5869 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
5870 }
5871 }
5872
5873 /* Adjust the this parameter by a value stored in the vtable. */
5874 if (vcall_offset)
5875 {
5876 rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
6ce986b9 5877 rtx tmp = gen_rtx_REG (Pmode, REG_R3);
0d4a78eb
BS
5878
5879 xops[1] = tmp;
5880 xops[2] = p2tmp;
5881 output_asm_insn ("%2 = r0; %2 = [%2];", xops);
5882
5883 /* Adjust the this parameter. */
5884 xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
5885 if (!memory_operand (xops[0], Pmode))
5886 {
5887 rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
5888 xops[0] = GEN_INT (vcall_offset);
5889 xops[1] = tmp2;
5890 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
5891 xops[0] = gen_rtx_MEM (Pmode, p2tmp);
5892 }
0a2aaacc 5893 xops[2] = this_rtx;
0d4a78eb
BS
5894 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
5895 }
5896
5897 xops[0] = XEXP (DECL_RTL (function), 0);
5898 if (1 || !flag_pic || (*targetm.binds_local_p) (function))
5899 output_asm_insn ("jump.l\t%P0", xops);
5900}
5901\f
9df3d545
BS
5902/* Codes for all the Blackfin builtins. */
5903enum bfin_builtins
5904{
5905 BFIN_BUILTIN_CSYNC,
5906 BFIN_BUILTIN_SSYNC,
1d7d5ac4 5907 BFIN_BUILTIN_ONES,
42da70b7
BS
5908 BFIN_BUILTIN_COMPOSE_2X16,
5909 BFIN_BUILTIN_EXTRACTLO,
5910 BFIN_BUILTIN_EXTRACTHI,
5911
5912 BFIN_BUILTIN_SSADD_2X16,
5913 BFIN_BUILTIN_SSSUB_2X16,
5914 BFIN_BUILTIN_SSADDSUB_2X16,
5915 BFIN_BUILTIN_SSSUBADD_2X16,
5916 BFIN_BUILTIN_MULT_2X16,
5917 BFIN_BUILTIN_MULTR_2X16,
5918 BFIN_BUILTIN_NEG_2X16,
5919 BFIN_BUILTIN_ABS_2X16,
5920 BFIN_BUILTIN_MIN_2X16,
5921 BFIN_BUILTIN_MAX_2X16,
5922
5923 BFIN_BUILTIN_SSADD_1X16,
5924 BFIN_BUILTIN_SSSUB_1X16,
5925 BFIN_BUILTIN_MULT_1X16,
5926 BFIN_BUILTIN_MULTR_1X16,
5927 BFIN_BUILTIN_NORM_1X16,
5928 BFIN_BUILTIN_NEG_1X16,
5929 BFIN_BUILTIN_ABS_1X16,
5930 BFIN_BUILTIN_MIN_1X16,
5931 BFIN_BUILTIN_MAX_1X16,
5932
26c5953d 5933 BFIN_BUILTIN_SUM_2X16,
42da70b7
BS
5934 BFIN_BUILTIN_DIFFHL_2X16,
5935 BFIN_BUILTIN_DIFFLH_2X16,
5936
5937 BFIN_BUILTIN_SSADD_1X32,
5938 BFIN_BUILTIN_SSSUB_1X32,
5939 BFIN_BUILTIN_NORM_1X32,
26c5953d 5940 BFIN_BUILTIN_ROUND_1X32,
42da70b7 5941 BFIN_BUILTIN_NEG_1X32,
26c5953d 5942 BFIN_BUILTIN_ABS_1X32,
42da70b7
BS
5943 BFIN_BUILTIN_MIN_1X32,
5944 BFIN_BUILTIN_MAX_1X32,
5945 BFIN_BUILTIN_MULT_1X32,
26c5953d
BS
5946 BFIN_BUILTIN_MULT_1X32X32,
5947 BFIN_BUILTIN_MULT_1X32X32NS,
42da70b7
BS
5948
5949 BFIN_BUILTIN_MULHISILL,
5950 BFIN_BUILTIN_MULHISILH,
5951 BFIN_BUILTIN_MULHISIHL,
5952 BFIN_BUILTIN_MULHISIHH,
5953
5954 BFIN_BUILTIN_LSHIFT_1X16,
5955 BFIN_BUILTIN_LSHIFT_2X16,
5956 BFIN_BUILTIN_SSASHIFT_1X16,
5957 BFIN_BUILTIN_SSASHIFT_2X16,
26c5953d 5958 BFIN_BUILTIN_SSASHIFT_1X32,
42da70b7
BS
5959
5960 BFIN_BUILTIN_CPLX_MUL_16,
5961 BFIN_BUILTIN_CPLX_MAC_16,
5962 BFIN_BUILTIN_CPLX_MSU_16,
5963
1d7d5ac4
BS
5964 BFIN_BUILTIN_CPLX_MUL_16_S40,
5965 BFIN_BUILTIN_CPLX_MAC_16_S40,
5966 BFIN_BUILTIN_CPLX_MSU_16_S40,
5967
5968 BFIN_BUILTIN_CPLX_SQU,
5969
8fa477f7
BS
5970 BFIN_BUILTIN_LOADBYTES,
5971
9df3d545
BS
5972 BFIN_BUILTIN_MAX
5973};
5974
05905337
BS
5975#define def_builtin(NAME, TYPE, CODE) \
5976do { \
c79efc4d
RÁE
5977 add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
5978 NULL, NULL_TREE); \
5fcead21
BS
5979} while (0)
5980
5981/* Set up all builtin functions for this target. */
5982static void
5983bfin_init_builtins (void)
5984{
42da70b7 5985 tree V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
5fcead21
BS
5986 tree void_ftype_void
5987 = build_function_type (void_type_node, void_list_node);
42da70b7
BS
5988 tree short_ftype_short
5989 = build_function_type_list (short_integer_type_node, short_integer_type_node,
5990 NULL_TREE);
5991 tree short_ftype_int_int
5992 = build_function_type_list (short_integer_type_node, integer_type_node,
5993 integer_type_node, NULL_TREE);
5994 tree int_ftype_int_int
5995 = build_function_type_list (integer_type_node, integer_type_node,
5996 integer_type_node, NULL_TREE);
5997 tree int_ftype_int
5998 = build_function_type_list (integer_type_node, integer_type_node,
5999 NULL_TREE);
6000 tree short_ftype_int
6001 = build_function_type_list (short_integer_type_node, integer_type_node,
6002 NULL_TREE);
6003 tree int_ftype_v2hi_v2hi
6004 = build_function_type_list (integer_type_node, V2HI_type_node,
6005 V2HI_type_node, NULL_TREE);
6006 tree v2hi_ftype_v2hi_v2hi
6007 = build_function_type_list (V2HI_type_node, V2HI_type_node,
6008 V2HI_type_node, NULL_TREE);
6009 tree v2hi_ftype_v2hi_v2hi_v2hi
6010 = build_function_type_list (V2HI_type_node, V2HI_type_node,
6011 V2HI_type_node, V2HI_type_node, NULL_TREE);
6012 tree v2hi_ftype_int_int
6013 = build_function_type_list (V2HI_type_node, integer_type_node,
6014 integer_type_node, NULL_TREE);
6015 tree v2hi_ftype_v2hi_int
6016 = build_function_type_list (V2HI_type_node, V2HI_type_node,
6017 integer_type_node, NULL_TREE);
6018 tree int_ftype_short_short
6019 = build_function_type_list (integer_type_node, short_integer_type_node,
6020 short_integer_type_node, NULL_TREE);
6021 tree v2hi_ftype_v2hi
6022 = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
6023 tree short_ftype_v2hi
6024 = build_function_type_list (short_integer_type_node, V2HI_type_node,
6025 NULL_TREE);
8fa477f7
BS
6026 tree int_ftype_pint
6027 = build_function_type_list (integer_type_node,
6028 build_pointer_type (integer_type_node),
6029 NULL_TREE);
6030
5fcead21
BS
6031 /* Add the remaining MMX insns with somewhat more complicated types. */
6032 def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
6033 def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
42da70b7 6034
1d7d5ac4
BS
6035 def_builtin ("__builtin_bfin_ones", short_ftype_int, BFIN_BUILTIN_ONES);
6036
42da70b7
BS
6037 def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int,
6038 BFIN_BUILTIN_COMPOSE_2X16);
6039 def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi,
6040 BFIN_BUILTIN_EXTRACTHI);
6041 def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi,
6042 BFIN_BUILTIN_EXTRACTLO);
6043
6044 def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi,
6045 BFIN_BUILTIN_MIN_2X16);
6046 def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi,
6047 BFIN_BUILTIN_MAX_2X16);
6048
6049 def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi,
6050 BFIN_BUILTIN_SSADD_2X16);
6051 def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi,
6052 BFIN_BUILTIN_SSSUB_2X16);
6053 def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi,
6054 BFIN_BUILTIN_SSADDSUB_2X16);
6055 def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi,
6056 BFIN_BUILTIN_SSSUBADD_2X16);
6057 def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi,
6058 BFIN_BUILTIN_MULT_2X16);
6059 def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi,
6060 BFIN_BUILTIN_MULTR_2X16);
6061 def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi,
6062 BFIN_BUILTIN_NEG_2X16);
6063 def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi,
6064 BFIN_BUILTIN_ABS_2X16);
6065
1d7d5ac4
BS
6066 def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int,
6067 BFIN_BUILTIN_MIN_1X16);
6068 def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int,
6069 BFIN_BUILTIN_MAX_1X16);
6070
42da70b7
BS
6071 def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int,
6072 BFIN_BUILTIN_SSADD_1X16);
6073 def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int,
6074 BFIN_BUILTIN_SSSUB_1X16);
6075 def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int,
6076 BFIN_BUILTIN_MULT_1X16);
6077 def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int,
6078 BFIN_BUILTIN_MULTR_1X16);
6079 def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short,
6080 BFIN_BUILTIN_NEG_1X16);
6081 def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short,
6082 BFIN_BUILTIN_ABS_1X16);
6083 def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int,
6084 BFIN_BUILTIN_NORM_1X16);
6085
26c5953d
BS
6086 def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi,
6087 BFIN_BUILTIN_SUM_2X16);
42da70b7
BS
6088 def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi,
6089 BFIN_BUILTIN_DIFFHL_2X16);
6090 def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi,
6091 BFIN_BUILTIN_DIFFLH_2X16);
6092
6093 def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi,
6094 BFIN_BUILTIN_MULHISILL);
6095 def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi,
6096 BFIN_BUILTIN_MULHISIHL);
6097 def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi,
6098 BFIN_BUILTIN_MULHISILH);
6099 def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi,
6100 BFIN_BUILTIN_MULHISIHH);
6101
1d7d5ac4
BS
6102 def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int,
6103 BFIN_BUILTIN_MIN_1X32);
6104 def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int,
6105 BFIN_BUILTIN_MAX_1X32);
6106
42da70b7
BS
6107 def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int,
6108 BFIN_BUILTIN_SSADD_1X32);
6109 def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int,
6110 BFIN_BUILTIN_SSSUB_1X32);
6111 def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int,
6112 BFIN_BUILTIN_NEG_1X32);
26c5953d
BS
6113 def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int,
6114 BFIN_BUILTIN_ABS_1X32);
42da70b7
BS
6115 def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int,
6116 BFIN_BUILTIN_NORM_1X32);
26c5953d
BS
6117 def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int,
6118 BFIN_BUILTIN_ROUND_1X32);
42da70b7
BS
6119 def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short,
6120 BFIN_BUILTIN_MULT_1X32);
26c5953d
BS
6121 def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int,
6122 BFIN_BUILTIN_MULT_1X32X32);
6123 def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int,
6124 BFIN_BUILTIN_MULT_1X32X32NS);
42da70b7
BS
6125
6126 /* Shifts. */
6127 def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int,
6128 BFIN_BUILTIN_SSASHIFT_1X16);
6129 def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int,
6130 BFIN_BUILTIN_SSASHIFT_2X16);
6131 def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int,
6132 BFIN_BUILTIN_LSHIFT_1X16);
6133 def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int,
6134 BFIN_BUILTIN_LSHIFT_2X16);
26c5953d
BS
6135 def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int,
6136 BFIN_BUILTIN_SSASHIFT_1X32);
42da70b7
BS
6137
6138 /* Complex numbers. */
1d7d5ac4
BS
6139 def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi,
6140 BFIN_BUILTIN_SSADD_2X16);
6141 def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi,
6142 BFIN_BUILTIN_SSSUB_2X16);
42da70b7
BS
6143 def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi,
6144 BFIN_BUILTIN_CPLX_MUL_16);
6145 def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi,
6146 BFIN_BUILTIN_CPLX_MAC_16);
6147 def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi,
6148 BFIN_BUILTIN_CPLX_MSU_16);
1d7d5ac4
BS
6149 def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi,
6150 BFIN_BUILTIN_CPLX_MUL_16_S40);
6151 def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi,
6152 BFIN_BUILTIN_CPLX_MAC_16_S40);
6153 def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi,
6154 BFIN_BUILTIN_CPLX_MSU_16_S40);
6155 def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi,
6156 BFIN_BUILTIN_CPLX_SQU);
8fa477f7
BS
6157
6158 /* "Unaligned" load. */
6159 def_builtin ("__builtin_bfin_loadbytes", int_ftype_pint,
6160 BFIN_BUILTIN_LOADBYTES);
6161
42da70b7
BS
6162}
6163
6164
6165struct builtin_description
6166{
6167 const enum insn_code icode;
6168 const char *const name;
6169 const enum bfin_builtins code;
6170 int macflag;
6171};
6172
6173static const struct builtin_description bdesc_2arg[] =
6174{
6175 { CODE_FOR_composev2hi, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16, -1 },
6176
6177 { CODE_FOR_ssashiftv2hi3, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16, -1 },
6178 { CODE_FOR_ssashifthi3, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16, -1 },
6179 { CODE_FOR_lshiftv2hi3, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16, -1 },
6180 { CODE_FOR_lshifthi3, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16, -1 },
26c5953d 6181 { CODE_FOR_ssashiftsi3, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32, -1 },
42da70b7
BS
6182
6183 { CODE_FOR_sminhi3, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16, -1 },
6184 { CODE_FOR_smaxhi3, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16, -1 },
6185 { CODE_FOR_ssaddhi3, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16, -1 },
6186 { CODE_FOR_sssubhi3, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16, -1 },
6187
6188 { CODE_FOR_sminsi3, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32, -1 },
6189 { CODE_FOR_smaxsi3, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32, -1 },
6190 { CODE_FOR_ssaddsi3, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32, -1 },
6191 { CODE_FOR_sssubsi3, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32, -1 },
6192
6193 { CODE_FOR_sminv2hi3, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16, -1 },
6194 { CODE_FOR_smaxv2hi3, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16, -1 },
6195 { CODE_FOR_ssaddv2hi3, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16, -1 },
6196 { CODE_FOR_sssubv2hi3, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16, -1 },
6197 { CODE_FOR_ssaddsubv2hi3, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16, -1 },
6198 { CODE_FOR_sssubaddv2hi3, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16, -1 },
6199
6200 { CODE_FOR_flag_mulhisi, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32, MACFLAG_NONE },
6201 { CODE_FOR_flag_mulhi, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16, MACFLAG_T },
6202 { CODE_FOR_flag_mulhi, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16, MACFLAG_NONE },
6203 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16, MACFLAG_T },
2aca912d
BS
6204 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16, MACFLAG_NONE },
6205
6206 { CODE_FOR_mulhisi_ll, "__builtin_bfin_mulhisill", BFIN_BUILTIN_MULHISILL, -1 },
6207 { CODE_FOR_mulhisi_lh, "__builtin_bfin_mulhisilh", BFIN_BUILTIN_MULHISILH, -1 },
6208 { CODE_FOR_mulhisi_hl, "__builtin_bfin_mulhisihl", BFIN_BUILTIN_MULHISIHL, -1 },
6209 { CODE_FOR_mulhisi_hh, "__builtin_bfin_mulhisihh", BFIN_BUILTIN_MULHISIHH, -1 }
6210
42da70b7
BS
6211};
6212
6213static const struct builtin_description bdesc_1arg[] =
6214{
8fa477f7
BS
6215 { CODE_FOR_loadbytes, "__builtin_bfin_loadbytes", BFIN_BUILTIN_LOADBYTES, 0 },
6216
1d7d5ac4
BS
6217 { CODE_FOR_ones, "__builtin_bfin_ones", BFIN_BUILTIN_ONES, 0 },
6218
42da70b7
BS
6219 { CODE_FOR_signbitshi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 },
6220 { CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 },
6221 { CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 },
6222
6223 { CODE_FOR_signbitssi2, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32, 0 },
26c5953d 6224 { CODE_FOR_ssroundsi2, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32, 0 },
42da70b7 6225 { CODE_FOR_ssnegsi2, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32, 0 },
26c5953d 6226 { CODE_FOR_ssabssi2, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32, 0 },
42da70b7
BS
6227
6228 { CODE_FOR_movv2hi_hi_low, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO, 0 },
6229 { CODE_FOR_movv2hi_hi_high, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI, 0 },
6230 { CODE_FOR_ssnegv2hi2, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16, 0 },
26c5953d 6231 { CODE_FOR_ssabsv2hi2, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16, 0 }
42da70b7
BS
6232};
6233
6234/* Errors in the source file can cause expand_expr to return const0_rtx
6235 where we expect a vector. To avoid crashing, use one of the vector
6236 clear instructions. */
6237static rtx
6238safe_vector_operand (rtx x, enum machine_mode mode)
6239{
6240 if (x != const0_rtx)
6241 return x;
6242 x = gen_reg_rtx (SImode);
6243
6244 emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
6245 return gen_lowpart (mode, x);
6246}
6247
6248/* Subroutine of bfin_expand_builtin to take care of binop insns. MACFLAG is -1
6249 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
6250
6251static rtx
5039610b 6252bfin_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
42da70b7
BS
6253 int macflag)
6254{
6255 rtx pat;
5039610b
SL
6256 tree arg0 = CALL_EXPR_ARG (exp, 0);
6257 tree arg1 = CALL_EXPR_ARG (exp, 1);
d3c176fc
JR
6258 rtx op0 = expand_normal (arg0);
6259 rtx op1 = expand_normal (arg1);
42da70b7
BS
6260 enum machine_mode op0mode = GET_MODE (op0);
6261 enum machine_mode op1mode = GET_MODE (op1);
6262 enum machine_mode tmode = insn_data[icode].operand[0].mode;
6263 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
6264 enum machine_mode mode1 = insn_data[icode].operand[2].mode;
6265
6266 if (VECTOR_MODE_P (mode0))
6267 op0 = safe_vector_operand (op0, mode0);
6268 if (VECTOR_MODE_P (mode1))
6269 op1 = safe_vector_operand (op1, mode1);
6270
6271 if (! target
6272 || GET_MODE (target) != tmode
6273 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6274 target = gen_reg_rtx (tmode);
6275
6276 if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode)
6277 {
6278 op0mode = HImode;
6279 op0 = gen_lowpart (HImode, op0);
6280 }
6281 if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode)
6282 {
6283 op1mode = HImode;
6284 op1 = gen_lowpart (HImode, op1);
6285 }
6286 /* In case the insn wants input operands in modes different from
6287 the result, abort. */
6288 gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
6289 && (op1mode == mode1 || op1mode == VOIDmode));
6290
6291 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6292 op0 = copy_to_mode_reg (mode0, op0);
6293 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
6294 op1 = copy_to_mode_reg (mode1, op1);
6295
6296 if (macflag == -1)
6297 pat = GEN_FCN (icode) (target, op0, op1);
6298 else
6299 pat = GEN_FCN (icode) (target, op0, op1, GEN_INT (macflag));
6300 if (! pat)
6301 return 0;
6302
6303 emit_insn (pat);
6304 return target;
6305}
6306
6307/* Subroutine of bfin_expand_builtin to take care of unop insns. */
6308
6309static rtx
5039610b 6310bfin_expand_unop_builtin (enum insn_code icode, tree exp,
42da70b7
BS
6311 rtx target)
6312{
6313 rtx pat;
5039610b 6314 tree arg0 = CALL_EXPR_ARG (exp, 0);
d3c176fc 6315 rtx op0 = expand_normal (arg0);
42da70b7
BS
6316 enum machine_mode op0mode = GET_MODE (op0);
6317 enum machine_mode tmode = insn_data[icode].operand[0].mode;
6318 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
6319
6320 if (! target
6321 || GET_MODE (target) != tmode
6322 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6323 target = gen_reg_rtx (tmode);
6324
6325 if (VECTOR_MODE_P (mode0))
6326 op0 = safe_vector_operand (op0, mode0);
6327
6328 if (op0mode == SImode && mode0 == HImode)
6329 {
6330 op0mode = HImode;
6331 op0 = gen_lowpart (HImode, op0);
6332 }
6333 gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
6334
6335 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6336 op0 = copy_to_mode_reg (mode0, op0);
6337
6338 pat = GEN_FCN (icode) (target, op0);
6339 if (! pat)
6340 return 0;
6341 emit_insn (pat);
6342 return target;
5fcead21
BS
6343}
6344
6345/* Expand an expression EXP that calls a built-in function,
6346 with result going to TARGET if that's convenient
6347 (and in mode MODE if that's convenient).
6348 SUBTARGET may be used as the target for computing one of EXP's operands.
6349 IGNORE is nonzero if the value is to be ignored. */
6350
6351static rtx
6352bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6353 rtx subtarget ATTRIBUTE_UNUSED,
6354 enum machine_mode mode ATTRIBUTE_UNUSED,
6355 int ignore ATTRIBUTE_UNUSED)
6356{
42da70b7
BS
6357 size_t i;
6358 enum insn_code icode;
6359 const struct builtin_description *d;
5039610b 6360 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
5fcead21 6361 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
42da70b7 6362 tree arg0, arg1, arg2;
26c5953d 6363 rtx op0, op1, op2, accvec, pat, tmp1, tmp2, a0reg, a1reg;
42da70b7 6364 enum machine_mode tmode, mode0;
5fcead21
BS
6365
6366 switch (fcode)
6367 {
6368 case BFIN_BUILTIN_CSYNC:
6369 emit_insn (gen_csync ());
6370 return 0;
6371 case BFIN_BUILTIN_SSYNC:
6372 emit_insn (gen_ssync ());
6373 return 0;
6374
42da70b7
BS
6375 case BFIN_BUILTIN_DIFFHL_2X16:
6376 case BFIN_BUILTIN_DIFFLH_2X16:
26c5953d 6377 case BFIN_BUILTIN_SUM_2X16:
5039610b 6378 arg0 = CALL_EXPR_ARG (exp, 0);
d3c176fc 6379 op0 = expand_normal (arg0);
26c5953d
BS
6380 icode = (fcode == BFIN_BUILTIN_DIFFHL_2X16 ? CODE_FOR_subhilov2hi3
6381 : fcode == BFIN_BUILTIN_DIFFLH_2X16 ? CODE_FOR_sublohiv2hi3
6382 : CODE_FOR_ssaddhilov2hi3);
42da70b7
BS
6383 tmode = insn_data[icode].operand[0].mode;
6384 mode0 = insn_data[icode].operand[1].mode;
6385
6386 if (! target
6387 || GET_MODE (target) != tmode
6388 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6389 target = gen_reg_rtx (tmode);
6390
6391 if (VECTOR_MODE_P (mode0))
6392 op0 = safe_vector_operand (op0, mode0);
6393
6394 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6395 op0 = copy_to_mode_reg (mode0, op0);
6396
6397 pat = GEN_FCN (icode) (target, op0, op0);
6398 if (! pat)
6399 return 0;
6400 emit_insn (pat);
6401 return target;
6402
26c5953d
BS
6403 case BFIN_BUILTIN_MULT_1X32X32:
6404 case BFIN_BUILTIN_MULT_1X32X32NS:
6405 arg0 = CALL_EXPR_ARG (exp, 0);
6406 arg1 = CALL_EXPR_ARG (exp, 1);
d3c176fc
JR
6407 op0 = expand_normal (arg0);
6408 op1 = expand_normal (arg1);
26c5953d
BS
6409 if (! target
6410 || !register_operand (target, SImode))
6411 target = gen_reg_rtx (SImode);
6c1c1dfa
BS
6412 if (! register_operand (op0, SImode))
6413 op0 = copy_to_mode_reg (SImode, op0);
6414 if (! register_operand (op1, SImode))
6415 op1 = copy_to_mode_reg (SImode, op1);
26c5953d
BS
6416
6417 a1reg = gen_rtx_REG (PDImode, REG_A1);
6418 a0reg = gen_rtx_REG (PDImode, REG_A0);
6419 tmp1 = gen_lowpart (V2HImode, op0);
6420 tmp2 = gen_lowpart (V2HImode, op1);
6421 emit_insn (gen_flag_macinit1hi (a1reg,
6422 gen_lowpart (HImode, op0),
6423 gen_lowpart (HImode, op1),
6424 GEN_INT (MACFLAG_FU)));
6425 emit_insn (gen_lshrpdi3 (a1reg, a1reg, GEN_INT (16)));
6426
6427 if (fcode == BFIN_BUILTIN_MULT_1X32X32)
6428 emit_insn (gen_flag_mul_macv2hi_parts_acconly (a0reg, a1reg, tmp1, tmp2,
6429 const1_rtx, const1_rtx,
6430 const1_rtx, const0_rtx, a1reg,
6431 const0_rtx, GEN_INT (MACFLAG_NONE),
6432 GEN_INT (MACFLAG_M)));
6433 else
6434 {
6435 /* For saturating multiplication, there's exactly one special case
6436 to be handled: multiplying the smallest negative value with
6437 itself. Due to shift correction in fractional multiplies, this
6438 can overflow. Iff this happens, OP2 will contain 1, which, when
6439 added in 32 bits to the smallest negative, wraps to the largest
6440 positive, which is the result we want. */
6441 op2 = gen_reg_rtx (V2HImode);
6442 emit_insn (gen_packv2hi (op2, tmp1, tmp2, const0_rtx, const0_rtx));
6443 emit_insn (gen_movsibi (gen_rtx_REG (BImode, REG_CC),
6444 gen_lowpart (SImode, op2)));
6445 emit_insn (gen_flag_mul_macv2hi_parts_acconly_andcc0 (a0reg, a1reg, tmp1, tmp2,
6446 const1_rtx, const1_rtx,
6447 const1_rtx, const0_rtx, a1reg,
6448 const0_rtx, GEN_INT (MACFLAG_NONE),
6449 GEN_INT (MACFLAG_M)));
6450 op2 = gen_reg_rtx (SImode);
6451 emit_insn (gen_movbisi (op2, gen_rtx_REG (BImode, REG_CC)));
6452 }
6453 emit_insn (gen_flag_machi_parts_acconly (a1reg, tmp2, tmp1,
6454 const1_rtx, const0_rtx,
6455 a1reg, const0_rtx, GEN_INT (MACFLAG_M)));
6456 emit_insn (gen_ashrpdi3 (a1reg, a1reg, GEN_INT (15)));
6457 emit_insn (gen_sum_of_accumulators (target, a0reg, a0reg, a1reg));
6458 if (fcode == BFIN_BUILTIN_MULT_1X32X32NS)
6459 emit_insn (gen_addsi3 (target, target, op2));
6460 return target;
6461
42da70b7 6462 case BFIN_BUILTIN_CPLX_MUL_16:
1d7d5ac4 6463 case BFIN_BUILTIN_CPLX_MUL_16_S40:
5039610b
SL
6464 arg0 = CALL_EXPR_ARG (exp, 0);
6465 arg1 = CALL_EXPR_ARG (exp, 1);
d3c176fc
JR
6466 op0 = expand_normal (arg0);
6467 op1 = expand_normal (arg1);
42da70b7 6468 accvec = gen_reg_rtx (V2PDImode);
6c1c1dfa 6469 icode = CODE_FOR_flag_macv2hi_parts;
d3c176fc 6470 tmode = insn_data[icode].operand[0].mode;
42da70b7
BS
6471
6472 if (! target
6473 || GET_MODE (target) != V2HImode
6474 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6475 target = gen_reg_rtx (tmode);
6476 if (! register_operand (op0, GET_MODE (op0)))
6477 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6478 if (! register_operand (op1, GET_MODE (op1)))
6479 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6480
1d7d5ac4
BS
6481 if (fcode == BFIN_BUILTIN_CPLX_MUL_16)
6482 emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6483 const0_rtx, const0_rtx,
6484 const1_rtx, GEN_INT (MACFLAG_W32)));
6485 else
6486 emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6487 const0_rtx, const0_rtx,
6488 const1_rtx, GEN_INT (MACFLAG_NONE)));
42da70b7
BS
6489 emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
6490 const1_rtx, const1_rtx,
6491 const0_rtx, accvec, const1_rtx, const0_rtx,
6492 GEN_INT (MACFLAG_NONE), accvec));
6493
6494 return target;
6495
6496 case BFIN_BUILTIN_CPLX_MAC_16:
6497 case BFIN_BUILTIN_CPLX_MSU_16:
1d7d5ac4
BS
6498 case BFIN_BUILTIN_CPLX_MAC_16_S40:
6499 case BFIN_BUILTIN_CPLX_MSU_16_S40:
5039610b
SL
6500 arg0 = CALL_EXPR_ARG (exp, 0);
6501 arg1 = CALL_EXPR_ARG (exp, 1);
6502 arg2 = CALL_EXPR_ARG (exp, 2);
d3c176fc
JR
6503 op0 = expand_normal (arg0);
6504 op1 = expand_normal (arg1);
6505 op2 = expand_normal (arg2);
42da70b7 6506 accvec = gen_reg_rtx (V2PDImode);
6c1c1dfa 6507 icode = CODE_FOR_flag_macv2hi_parts;
d3c176fc 6508 tmode = insn_data[icode].operand[0].mode;
42da70b7
BS
6509
6510 if (! target
6511 || GET_MODE (target) != V2HImode
6512 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6513 target = gen_reg_rtx (tmode);
42da70b7
BS
6514 if (! register_operand (op1, GET_MODE (op1)))
6515 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
48ccf012
JZ
6516 if (! register_operand (op2, GET_MODE (op2)))
6517 op2 = copy_to_mode_reg (GET_MODE (op2), op2);
42da70b7
BS
6518
6519 tmp1 = gen_reg_rtx (SImode);
6520 tmp2 = gen_reg_rtx (SImode);
48ccf012
JZ
6521 emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op0), GEN_INT (16)));
6522 emit_move_insn (tmp2, gen_lowpart (SImode, op0));
42da70b7
BS
6523 emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx));
6524 emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2));
1d7d5ac4
BS
6525 if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6526 || fcode == BFIN_BUILTIN_CPLX_MSU_16)
6527 emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6528 const0_rtx, const0_rtx,
6529 const1_rtx, accvec, const0_rtx,
6530 const0_rtx,
6531 GEN_INT (MACFLAG_W32)));
6532 else
6533 emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6534 const0_rtx, const0_rtx,
6535 const1_rtx, accvec, const0_rtx,
6536 const0_rtx,
6537 GEN_INT (MACFLAG_NONE)));
6538 if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6539 || fcode == BFIN_BUILTIN_CPLX_MAC_16_S40)
6540 {
6541 tmp1 = const1_rtx;
6542 tmp2 = const0_rtx;
6543 }
6544 else
6545 {
6546 tmp1 = const0_rtx;
6547 tmp2 = const1_rtx;
6548 }
48ccf012 6549 emit_insn (gen_flag_macv2hi_parts (target, op1, op2, const1_rtx,
42da70b7
BS
6550 const1_rtx, const1_rtx,
6551 const0_rtx, accvec, tmp1, tmp2,
6552 GEN_INT (MACFLAG_NONE), accvec));
6553
6554 return target;
6555
1d7d5ac4
BS
6556 case BFIN_BUILTIN_CPLX_SQU:
6557 arg0 = CALL_EXPR_ARG (exp, 0);
d3c176fc 6558 op0 = expand_normal (arg0);
1d7d5ac4
BS
6559 accvec = gen_reg_rtx (V2PDImode);
6560 icode = CODE_FOR_flag_mulv2hi;
6561 tmp1 = gen_reg_rtx (V2HImode);
6562 tmp2 = gen_reg_rtx (V2HImode);
6563
6564 if (! target
6565 || GET_MODE (target) != V2HImode
6566 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6567 target = gen_reg_rtx (V2HImode);
6568 if (! register_operand (op0, GET_MODE (op0)))
6569 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6570
6571 emit_insn (gen_flag_mulv2hi (tmp1, op0, op0, GEN_INT (MACFLAG_NONE)));
6572
a0a31d1e 6573 emit_insn (gen_flag_mulhi_parts (gen_lowpart (HImode, tmp2), op0, op0,
1d7d5ac4
BS
6574 const0_rtx, const1_rtx,
6575 GEN_INT (MACFLAG_NONE)));
6576
a0a31d1e
BS
6577 emit_insn (gen_ssaddhi3_high_parts (target, tmp2, tmp2, tmp2, const0_rtx,
6578 const0_rtx));
6579 emit_insn (gen_sssubhi3_low_parts (target, target, tmp1, tmp1,
6580 const0_rtx, const1_rtx));
1d7d5ac4
BS
6581
6582 return target;
6583
5fcead21 6584 default:
42da70b7 6585 break;
5fcead21 6586 }
42da70b7
BS
6587
6588 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
6589 if (d->code == fcode)
5039610b 6590 return bfin_expand_binop_builtin (d->icode, exp, target,
42da70b7
BS
6591 d->macflag);
6592
6593 for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
6594 if (d->code == fcode)
5039610b 6595 return bfin_expand_unop_builtin (d->icode, exp, target);
42da70b7
BS
6596
6597 gcc_unreachable ();
5fcead21 6598}
5efd84c5
NF
6599
6600static void
6601bfin_conditional_register_usage (void)
6602{
6603 /* initialize condition code flag register rtx */
6604 bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);
6605 bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);
6606 if (TARGET_FDPIC)
6607 call_used_regs[FDPIC_REGNO] = 1;
6608 if (!TARGET_FDPIC && flag_pic)
6609 {
6610 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
6611 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
6612 }
6613}
5fcead21
BS
6614\f
6615#undef TARGET_INIT_BUILTINS
6616#define TARGET_INIT_BUILTINS bfin_init_builtins
6617
6618#undef TARGET_EXPAND_BUILTIN
6619#define TARGET_EXPAND_BUILTIN bfin_expand_builtin
6620
0d4a78eb
BS
6621#undef TARGET_ASM_GLOBALIZE_LABEL
6622#define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
6623
6624#undef TARGET_ASM_FILE_START
6625#define TARGET_ASM_FILE_START output_file_start
6626
6627#undef TARGET_ATTRIBUTE_TABLE
6628#define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
6629
6630#undef TARGET_COMP_TYPE_ATTRIBUTES
6631#define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
6632
6633#undef TARGET_RTX_COSTS
6634#define TARGET_RTX_COSTS bfin_rtx_costs
6635
6636#undef TARGET_ADDRESS_COST
6637#define TARGET_ADDRESS_COST bfin_address_cost
6638
6614f9f5
BS
6639#undef TARGET_ASM_INTEGER
6640#define TARGET_ASM_INTEGER bfin_assemble_integer
6641
0d4a78eb
BS
6642#undef TARGET_MACHINE_DEPENDENT_REORG
6643#define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
6644
6645#undef TARGET_FUNCTION_OK_FOR_SIBCALL
6646#define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
6647
6648#undef TARGET_ASM_OUTPUT_MI_THUNK
6649#define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
6650#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3101faab 6651#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
0d4a78eb
BS
6652
6653#undef TARGET_SCHED_ADJUST_COST
6654#define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
6655
36662eb1
BS
6656#undef TARGET_SCHED_ISSUE_RATE
6657#define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
6658
cde0f3fd
PB
6659#undef TARGET_PROMOTE_FUNCTION_MODE
6660#define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
0d4a78eb
BS
6661
6662#undef TARGET_ARG_PARTIAL_BYTES
6663#define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
6664
74f41f02
NF
6665#undef TARGET_FUNCTION_ARG
6666#define TARGET_FUNCTION_ARG bfin_function_arg
6667
6668#undef TARGET_FUNCTION_ARG_ADVANCE
6669#define TARGET_FUNCTION_ARG_ADVANCE bfin_function_arg_advance
6670
0d4a78eb
BS
6671#undef TARGET_PASS_BY_REFERENCE
6672#define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
6673
6674#undef TARGET_SETUP_INCOMING_VARARGS
6675#define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
6676
6677#undef TARGET_STRUCT_VALUE_RTX
6678#define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
6679
6680#undef TARGET_VECTOR_MODE_SUPPORTED_P
6681#define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
6682
f02a5d0e
BS
6683#undef TARGET_HANDLE_OPTION
6684#define TARGET_HANDLE_OPTION bfin_handle_option
6685
c5387660
JM
6686#undef TARGET_OPTION_OVERRIDE
6687#define TARGET_OPTION_OVERRIDE bfin_option_override
6688
3fb192d2
BS
6689#undef TARGET_DEFAULT_TARGET_FLAGS
6690#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
6691
e97f2058
BS
6692#undef TARGET_SECONDARY_RELOAD
6693#define TARGET_SECONDARY_RELOAD bfin_secondary_reload
6694
0b182178
AS
6695#undef TARGET_CLASS_LIKELY_SPILLED_P
6696#define TARGET_CLASS_LIKELY_SPILLED_P bfin_class_likely_spilled_p
6697
54aefc36
JZ
6698#undef TARGET_DELEGITIMIZE_ADDRESS
6699#define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
6700
d6f6753e
BS
6701#undef TARGET_CANNOT_FORCE_CONST_MEM
6702#define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
6703
7ba20e60
BS
6704#undef TARGET_RETURN_IN_MEMORY
6705#define TARGET_RETURN_IN_MEMORY bfin_return_in_memory
6706
c6c3dba9
PB
6707#undef TARGET_LEGITIMATE_ADDRESS_P
6708#define TARGET_LEGITIMATE_ADDRESS_P bfin_legitimate_address_p
6709
b52b1749
AS
6710#undef TARGET_FRAME_POINTER_REQUIRED
6711#define TARGET_FRAME_POINTER_REQUIRED bfin_frame_pointer_required
6712
7b5cbb57
AS
6713#undef TARGET_CAN_ELIMINATE
6714#define TARGET_CAN_ELIMINATE bfin_can_eliminate
6715
5efd84c5
NF
6716#undef TARGET_CONDITIONAL_REGISTER_USAGE
6717#define TARGET_CONDITIONAL_REGISTER_USAGE bfin_conditional_register_usage
6718
92910d77
RH
6719#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
6720#define TARGET_ASM_TRAMPOLINE_TEMPLATE bfin_asm_trampoline_template
6721#undef TARGET_TRAMPOLINE_INIT
6722#define TARGET_TRAMPOLINE_INIT bfin_trampoline_init
6723
0d4a78eb 6724struct gcc_target targetm = TARGET_INITIALIZER;