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