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