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