1 /* Subroutines used for code generation on Xilinx MicroBlaze. 2 Copyright (C) 2009-2020 Free Software Foundation, Inc. 3 4 Contributed by Michael Eager <eager@eagercon.com>. 5 6 This file is part of GCC. 7 8 GCC is free software; you can redistribute it and/or modify it 9 under the terms of the GNU General Public License as published 10 by the Free Software Foundation; either version 3, or (at your 11 option) any later version. 12 13 GCC is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 16 License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with GCC; see the file COPYING3. If not see 20 <http://www.gnu.org/licenses/>. */ 21 22 #define IN_TARGET_CODE 1 23 24 #include "config.h" 25 #include "system.h" 26 #include "coretypes.h" 27 #include "backend.h" 28 #include "target.h" 29 #include "rtl.h" 30 #include "tree.h" 31 #include "stringpool.h" 32 #include "attribs.h" 33 #include "df.h" 34 #include "memmodel.h" 35 #include "tm_p.h" 36 #include "optabs.h" 37 #include "regs.h" 38 #include "emit-rtl.h" 39 #include "recog.h" 40 #include "cgraph.h" 41 #include "diagnostic-core.h" 42 #include "varasm.h" 43 #include "stor-layout.h" 44 #include "calls.h" 45 #include "explow.h" 46 #include "expr.h" 47 #include "reload.h" 48 #include "output.h" 49 #include "builtins.h" 50 #include "rtl-iter.h" 51 #include "cfgloop.h" 52 #include "insn-addr.h" 53 #include "cfgrtl.h" 54 55 /* This file should be included last. */ 56 #include "target-def.h" 57 58 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB) 59 60 /* Classifies an address. 61 62 ADDRESS_INVALID 63 An invalid address. 64 65 ADDRESS_REG 66 67 A natural register or a register + const_int offset address. 68 The register satisfies microblaze_valid_base_register_p and the 69 offset is a const_arith_operand. 70 71 ADDRESS_REG_INDEX 72 73 A natural register offset by the index contained in an index register. The base 74 register satisfies microblaze_valid_base_register_p and the index register 75 satisfies microblaze_valid_index_register_p 76 77 ADDRESS_CONST_INT 78 79 A signed 16/32-bit constant address. 80 81 ADDRESS_SYMBOLIC: 82 83 A constant symbolic address or a (register + symbol). */ 84 85 enum microblaze_address_type 86 { 87 ADDRESS_INVALID, 88 ADDRESS_REG, 89 ADDRESS_REG_INDEX, 90 ADDRESS_CONST_INT, 91 ADDRESS_SYMBOLIC, 92 ADDRESS_GOTOFF, 93 ADDRESS_PLT, 94 ADDRESS_TLS, 95 ADDRESS_SYMBOLIC_TXT_REL 96 }; 97 98 /* Classifies symbols 99 100 SYMBOL_TYPE_GENERAL 101 102 A general symbol. */ 103 enum microblaze_symbol_type 104 { 105 SYMBOL_TYPE_INVALID, 106 SYMBOL_TYPE_GENERAL 107 }; 108 109 /* TLS Address Type. */ 110 enum tls_reloc { 111 TLS_GD, 112 TLS_LDM, 113 TLS_DTPREL, 114 TLS_IE, 115 TLS_LE 116 }; 117 118 /* Classification of a MicroBlaze address. */ 119 struct microblaze_address_info 120 { 121 enum microblaze_address_type type; 122 rtx regA; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX, 123 ADDRESS_SYMBOLIC. */ 124 rtx regB; /* Contains valid values on ADDRESS_REG_INDEX. */ 125 rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */ 126 rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */ 127 enum microblaze_symbol_type symbol_type; 128 enum tls_reloc tls_type; 129 }; 130 131 /* Structure to be filled in by compute_frame_size with register 132 save masks, and offsets for the current function. */ 133 134 struct GTY(()) microblaze_frame_info { 135 long total_size; /* # bytes that the entire frame takes up. */ 136 long var_size; /* # bytes that variables take up. */ 137 long args_size; /* # bytes that outgoing arguments take up. */ 138 int link_debug_size; /* # bytes for the link reg and back pointer. */ 139 int gp_reg_size; /* # bytes needed to store gp regs. */ 140 long gp_offset; /* offset from new sp to store gp registers. */ 141 long mask; /* mask of saved gp registers. */ 142 int initialized; /* != 0 if frame size already calculated. */ 143 int num_gp; /* number of gp registers saved. */ 144 long insns_len; /* length of insns. */ 145 int alloc_stack; /* Flag to indicate if the current function 146 must not create stack space. (As an optimization). */ 147 }; 148 149 /* Global variables for machine-dependent things. */ 150 151 /* Toggle which pipleline interface to use. */ 152 static GTY(()) int microblaze_sched_use_dfa = 0; 153 154 /* Threshold for data being put into the small data/bss area, instead 155 of the normal data area (references to the small data/bss area take 156 1 instruction, and use the global pointer, references to the normal 157 data area takes 2 instructions). */ 158 int microblaze_section_threshold = -1; 159 160 /* Prevent scheduling potentially exception causing instructions in 161 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */ 162 int microblaze_no_unsafe_delay; 163 164 /* Set to one if the targeted core has the CLZ insn. */ 165 int microblaze_has_clz = 0; 166 167 /* Which CPU pipeline do we use. We haven't really standardized on a CPU 168 version having only a particular type of pipeline. There can still be 169 options on the CPU to scale pipeline features up or down. :( 170 Bad Presentation (??), so we let the MD file rely on the value of 171 this variable instead Making PIPE_5 the default. It should be backward 172 optimal with PIPE_3 MicroBlazes. */ 173 enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5; 174 175 /* High and low marks for floating point values which we will accept 176 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are 177 initialized in override_options. */ 178 REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow; 179 180 /* Array giving truth value on whether or not a given hard register 181 can support a given mode. */ 182 static char microblaze_hard_regno_mode_ok_p[(int)MAX_MACHINE_MODE] 183 [FIRST_PSEUDO_REGISTER]; 184 185 /* Current frame information calculated by compute_frame_size. */ 186 struct microblaze_frame_info current_frame_info; 187 188 /* Zero structure to initialize current_frame_info. */ 189 struct microblaze_frame_info zero_frame_info; 190 191 /* List of all MICROBLAZE punctuation characters used by print_operand. */ 192 char microblaze_print_operand_punct[256]; 193 194 /* Map GCC register number to debugger register number. */ 195 int microblaze_dbx_regno[FIRST_PSEUDO_REGISTER]; 196 197 /* Map hard register number to register class. */ 198 enum reg_class microblaze_regno_to_class[] = 199 { 200 GR_REGS, GR_REGS, GR_REGS, GR_REGS, 201 GR_REGS, GR_REGS, GR_REGS, GR_REGS, 202 GR_REGS, GR_REGS, GR_REGS, GR_REGS, 203 GR_REGS, GR_REGS, GR_REGS, GR_REGS, 204 GR_REGS, GR_REGS, GR_REGS, GR_REGS, 205 GR_REGS, GR_REGS, GR_REGS, GR_REGS, 206 GR_REGS, GR_REGS, GR_REGS, GR_REGS, 207 GR_REGS, GR_REGS, GR_REGS, GR_REGS, 208 ST_REGS, GR_REGS, GR_REGS, GR_REGS 209 }; 210 211 /* MicroBlaze specific machine attributes. 212 interrupt_handler - Interrupt handler attribute to add interrupt prologue 213 and epilogue and use appropriate interrupt return. 214 save_volatiles - Similar to interrupt handler, but use normal return. */ 215 int interrupt_handler; 216 int break_handler; 217 int fast_interrupt; 218 int save_volatiles; 219 220 const struct attribute_spec microblaze_attribute_table[] = { 221 /* name min_len, max_len, decl_req, type_req, fn_type_req, 222 affects_type_identity, handler, exclude */ 223 {"interrupt_handler", 0, 0, true, false, false, false, NULL, NULL }, 224 {"break_handler", 0, 0, true, false, false, false, NULL, NULL }, 225 {"fast_interrupt", 0, 0, true, false, false, false, NULL, NULL }, 226 {"save_volatiles", 0, 0, true, false, false, false, NULL, NULL }, 227 { NULL, 0, 0, false, false, false, false, NULL, NULL } 228 }; 229 230 static int microblaze_interrupt_function_p (tree); 231 232 static void microblaze_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED; 233 static void microblaze_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED; 234 235 section *sdata2_section; 236 237 #ifdef HAVE_AS_TLS 238 #undef TARGET_HAVE_TLS 239 #define TARGET_HAVE_TLS true 240 #endif 241 242 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */ 243 static bool 244 microblaze_const_double_ok (rtx op, machine_mode mode) 245 { 246 REAL_VALUE_TYPE d; 247 248 if (GET_CODE (op) != CONST_DOUBLE) 249 return 0; 250 251 if (GET_MODE (op) == VOIDmode) 252 return 1; 253 254 if (mode != SFmode && mode != DFmode) 255 return 0; 256 257 if (op == CONST0_RTX (mode)) 258 return 1; 259 260 d = *CONST_DOUBLE_REAL_VALUE (op); 261 262 if (REAL_VALUE_ISNAN (d)) 263 return FALSE; 264 265 if (REAL_VALUE_NEGATIVE (d)) 266 d = real_value_negate (&d); 267 268 if (mode == DFmode) 269 { 270 if (real_less (&d, &dfhigh) && real_less (&dflow, &d)) 271 return 1; 272 } 273 else 274 { 275 if (real_less (&d, &sfhigh) && real_less (&sflow, &d)) 276 return 1; 277 } 278 279 return 0; 280 } 281 282 /* Return truth value if a memory operand fits in a single instruction 283 (ie, register + small offset) or (register + register). */ 284 285 int 286 simple_memory_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED) 287 { 288 rtx addr, plus0, plus1; 289 290 /* Eliminate non-memory operations. */ 291 if (GET_CODE (op) != MEM) 292 return 0; 293 294 /* dword operations really put out 2 instructions, so eliminate them. */ 295 /* ??? This isn't strictly correct. It is OK to accept multiword modes 296 here, since the length attributes are being set correctly, but only 297 if the address is offsettable. */ 298 if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD) 299 return 0; 300 301 302 /* Decode the address now. */ 303 addr = XEXP (op, 0); 304 switch (GET_CODE (addr)) 305 306 { 307 case REG: 308 return 1; 309 310 case PLUS: 311 plus0 = XEXP (addr, 0); 312 plus1 = XEXP (addr, 1); 313 314 if (GET_CODE (plus0) != REG) 315 return 0; 316 317 if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT 318 && SMALL_INT (plus1)) 319 { 320 return 1; 321 } 322 else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT) 323 { 324 return 1; 325 } 326 else if (GET_CODE (plus0) == REG && GET_CODE (plus1) == REG) 327 { 328 return 1; 329 } 330 else 331 return 0; 332 333 case SYMBOL_REF: 334 return 0; 335 336 default: 337 break; 338 } 339 340 return 0; 341 } 342 343 /* Return nonzero for a memory address that can be used to load or store 344 a doubleword. */ 345 346 int 347 double_memory_operand (rtx op, machine_mode mode) 348 { 349 rtx addr; 350 351 if (GET_CODE (op) != MEM || !memory_operand (op, mode)) 352 { 353 /* During reload, we accept a pseudo register if it has an 354 appropriate memory address. If we don't do this, we will 355 wind up reloading into a register, and then reloading that 356 register from memory, when we could just reload directly from 357 memory. */ 358 if (reload_in_progress 359 && GET_CODE (op) == REG 360 && REGNO (op) >= FIRST_PSEUDO_REGISTER 361 && reg_renumber[REGNO (op)] < 0 362 && reg_equiv_mem (REGNO (op)) != 0 363 && double_memory_operand (reg_equiv_mem (REGNO (op)), mode)) 364 return 1; 365 return 0; 366 } 367 368 /* Make sure that 4 added to the address is a valid memory address. 369 This essentially just checks for overflow in an added constant. */ 370 371 addr = XEXP (op, 0); 372 373 if (CONSTANT_ADDRESS_P (addr)) 374 return 1; 375 376 return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT 377 ? E_SImode : E_SFmode), 378 plus_constant (Pmode, addr, 4)); 379 } 380 381 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */ 382 int 383 microblaze_regno_ok_for_base_p (int regno, int strict) 384 { 385 if (regno >= FIRST_PSEUDO_REGISTER) 386 { 387 if (!strict) 388 return true; 389 regno = reg_renumber[regno]; 390 } 391 392 /* These fake registers will be eliminated to either the stack or 393 hard frame pointer, both of which are usually valid base registers. 394 Reload deals with the cases where the eliminated form isn't valid. */ 395 if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM) 396 return true; 397 398 return GP_REG_P (regno); 399 } 400 401 /* Return true if X is a valid base register for the given mode. 402 Allow only hard registers if STRICT. */ 403 404 static bool 405 microblaze_valid_base_register_p (rtx x, 406 machine_mode mode ATTRIBUTE_UNUSED, 407 int strict) 408 { 409 if (!strict && GET_CODE (x) == SUBREG) 410 x = SUBREG_REG (x); 411 412 return (GET_CODE (x) == REG 413 && microblaze_regno_ok_for_base_p (REGNO (x), strict)); 414 } 415 416 /* Build the SYMBOL_REF for __tls_get_addr. */ 417 418 static GTY(()) rtx tls_get_addr_libfunc; 419 420 static rtx 421 get_tls_get_addr (void) 422 { 423 if (!tls_get_addr_libfunc) 424 tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr"); 425 return tls_get_addr_libfunc; 426 } 427 428 /* Return TRUE if X is a thread-local symbol. */ 429 bool 430 microblaze_tls_symbol_p (rtx x) 431 { 432 if (!TARGET_HAVE_TLS) 433 return false; 434 435 if (GET_CODE (x) != SYMBOL_REF) 436 return false; 437 438 return SYMBOL_REF_TLS_MODEL (x) != 0; 439 } 440 441 /* Return TRUE if X contains any TLS symbol references. */ 442 443 bool 444 microblaze_tls_referenced_p (rtx x) 445 { 446 if (!TARGET_HAVE_TLS) 447 return false; 448 subrtx_iterator::array_type array; 449 FOR_EACH_SUBRTX (iter, array, x, ALL) 450 { 451 const_rtx x = *iter; 452 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0) 453 return true; 454 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are 455 TLS offsets, not real symbol references. */ 456 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS) 457 iter.skip_subrtxes (); 458 } 459 return false; 460 } 461 462 bool 463 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x) 464 { 465 return microblaze_tls_referenced_p(x); 466 } 467 468 /* Return TRUE if X references a SYMBOL_REF. */ 469 int 470 symbol_mentioned_p (rtx x) 471 { 472 const char * fmt; 473 int i; 474 475 if (GET_CODE (x) == SYMBOL_REF) 476 return 1; 477 478 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they 479 are constant offsets, not symbols. */ 480 if (GET_CODE (x) == UNSPEC) 481 return 0; 482 483 fmt = GET_RTX_FORMAT (GET_CODE (x)); 484 485 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) 486 { 487 if (fmt[i] == 'E') 488 { 489 int j; 490 491 for (j = XVECLEN (x, i) - 1; j >= 0; j--) 492 if (symbol_mentioned_p (XVECEXP (x, i, j))) 493 return 1; 494 } 495 else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i))) 496 return 1; 497 } 498 499 return 0; 500 } 501 502 /* Return TRUE if X references a LABEL_REF. */ 503 int 504 label_mentioned_p (rtx x) 505 { 506 const char * fmt; 507 int i; 508 509 if (GET_CODE (x) == LABEL_REF) 510 return 1; 511 512 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing 513 instruction, but they are constant offsets, not symbols. */ 514 if (GET_CODE (x) == UNSPEC) 515 return 0; 516 517 fmt = GET_RTX_FORMAT (GET_CODE (x)); 518 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) 519 { 520 if (fmt[i] == 'E') 521 { 522 int j; 523 524 for (j = XVECLEN (x, i) - 1; j >= 0; j--) 525 if (label_mentioned_p (XVECEXP (x, i, j))) 526 return 1; 527 } 528 else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i))) 529 return 1; 530 } 531 532 return 0; 533 } 534 535 int 536 tls_mentioned_p (rtx x) 537 { 538 switch (GET_CODE (x)) 539 { 540 case CONST: 541 return tls_mentioned_p (XEXP (x, 0)); 542 543 case UNSPEC: 544 if (XINT (x, 1) == UNSPEC_TLS) 545 return 1; 546 return 0; 547 548 default: 549 return 0; 550 } 551 } 552 553 static rtx 554 load_tls_operand (rtx x, rtx reg) 555 { 556 rtx tmp; 557 558 if (reg == NULL_RTX) 559 reg = gen_reg_rtx (Pmode); 560 561 tmp = gen_rtx_CONST (Pmode, x); 562 563 emit_insn (gen_rtx_SET (reg, 564 gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp))); 565 566 return reg; 567 } 568 569 static rtx_insn * 570 microblaze_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc) 571 { 572 rtx_insn *insns; 573 rtx tls_entry; 574 575 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); 576 577 start_sequence (); 578 579 tls_entry = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)), 580 UNSPEC_TLS); 581 582 reg = load_tls_operand (tls_entry, reg); 583 584 *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX, 585 LCT_PURE, /* LCT_CONST? */ 586 Pmode, reg, Pmode); 587 588 insns = get_insns (); 589 end_sequence (); 590 591 return insns; 592 } 593 594 rtx 595 microblaze_legitimize_tls_address(rtx x, rtx reg) 596 { 597 rtx dest, ret, eqv, addend; 598 rtx_insn *insns; 599 enum tls_model model; 600 model = SYMBOL_REF_TLS_MODEL (x); 601 602 switch (model) 603 { 604 case TLS_MODEL_LOCAL_DYNAMIC: 605 case TLS_MODEL_GLOBAL_DYNAMIC: 606 case TLS_MODEL_INITIAL_EXEC: 607 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_GD); 608 dest = gen_reg_rtx (Pmode); 609 emit_libcall_block (insns, dest, ret, x); 610 break; 611 612 case TLS_MODEL_LOCAL_EXEC: 613 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_LDM); 614 615 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to 616 share the LDM result with other LD model accesses. */ 617 eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS); 618 dest = gen_reg_rtx (Pmode); 619 emit_libcall_block (insns, dest, ret, eqv); 620 621 /* Load the addend. */ 622 addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_DTPREL)), 623 UNSPEC_TLS); 624 addend = force_reg (SImode, gen_rtx_CONST (SImode, addend)); 625 dest = gen_rtx_PLUS (Pmode, dest, addend); 626 break; 627 628 default: 629 gcc_unreachable (); 630 } 631 return dest; 632 } 633 634 static bool 635 microblaze_classify_unspec (struct microblaze_address_info *info, rtx x) 636 { 637 info->symbol_type = SYMBOL_TYPE_GENERAL; 638 info->symbol = XVECEXP (x, 0, 0); 639 640 if (XINT (x, 1) == UNSPEC_GOTOFF) 641 { 642 info->regA = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM); 643 info->type = ADDRESS_GOTOFF; 644 } 645 else if (XINT (x, 1) == UNSPEC_PLT) 646 { 647 info->type = ADDRESS_PLT; 648 } 649 else if (XINT (x, 1) == UNSPEC_TLS) 650 { 651 info->type = ADDRESS_TLS; 652 info->tls_type = tls_reloc (INTVAL (XVECEXP (x, 0, 1))); 653 } 654 else if (XINT (x, 1) == UNSPEC_TEXT) 655 { 656 info->type = ADDRESS_SYMBOLIC_TXT_REL; 657 } 658 else 659 { 660 return false; 661 } 662 return true; 663 } 664 665 666 /* Return true if X is a valid index register for the given mode. 667 Allow only hard registers if STRICT. */ 668 669 static bool 670 microblaze_valid_index_register_p (rtx x, 671 machine_mode mode ATTRIBUTE_UNUSED, 672 int strict) 673 { 674 if (!strict && GET_CODE (x) == SUBREG) 675 x = SUBREG_REG (x); 676 677 return (GET_CODE (x) == REG 678 /* A base register is good enough to be an index register on MicroBlaze. */ 679 && microblaze_regno_ok_for_base_p (REGNO (x), strict)); 680 } 681 682 /* Get the base register for accessing a value from the memory or 683 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */ 684 static int 685 get_base_reg (rtx x) 686 { 687 tree decl; 688 int base_reg; 689 690 if (!flag_pic || microblaze_tls_symbol_p(x)) 691 base_reg = MB_ABI_BASE_REGNUM; 692 else if (flag_pic) 693 base_reg = MB_ABI_PIC_ADDR_REGNUM; 694 695 if (TARGET_XLGPOPT 696 && GET_CODE (x) == SYMBOL_REF 697 && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL) 698 { 699 if (TREE_READONLY (decl)) 700 base_reg = MB_ABI_GPRO_REGNUM; 701 else 702 base_reg = MB_ABI_GPRW_REGNUM; 703 } 704 705 return base_reg; 706 } 707 708 /* Return true if X is a valid address for machine mode MODE. If it is, 709 fill in INFO appropriately. 710 STRICT > 0 if we should only accept hard base registers. 711 STRICT = 2 if the operand address is being printed thus 712 function has been called by print_operand_address. 713 714 type regA regB offset symbol 715 716 ADDRESS_INVALID NULL NULL NULL NULL 717 718 ADDRESS_REG %0 NULL const_0 / NULL 719 const_int 720 ADDRESS_REG_INDEX %0 %1 NULL NULL 721 722 ADDRESS_SYMBOLIC r0 / NULL NULL symbol 723 sda_base_reg 724 725 ADDRESS_CONST_INT r0 NULL const NULL 726 727 For modes spanning multiple registers (DFmode in 32-bit GPRs, 728 DImode, TImode), indexed addressing cannot be used because 729 adjacent memory cells are accessed by adding word-sized offsets 730 during assembly output. */ 731 732 static bool 733 microblaze_classify_address (struct microblaze_address_info *info, rtx x, 734 machine_mode mode, int strict) 735 { 736 rtx xplus0; 737 rtx xplus1; 738 rtx offset; 739 740 info->type = ADDRESS_INVALID; 741 info->regA = NULL; 742 info->regB = NULL; 743 info->offset = NULL; 744 info->symbol = NULL; 745 info->symbol_type = SYMBOL_TYPE_INVALID; 746 offset = NULL; 747 748 switch (GET_CODE (x)) 749 { 750 case REG: 751 case SUBREG: 752 { 753 info->type = ADDRESS_REG; 754 info->regA = x; 755 info->offset = const0_rtx; 756 return microblaze_valid_base_register_p (info->regA, mode, strict); 757 } 758 case PLUS: 759 { 760 xplus0 = XEXP (x, 0); 761 xplus1 = XEXP (x, 1); 762 763 if (microblaze_valid_base_register_p (xplus0, mode, strict)) 764 { 765 info->type = ADDRESS_REG; 766 info->regA = xplus0; 767 768 if (GET_CODE (xplus1) == CONST_INT) 769 { 770 info->offset = xplus1; 771 return true; 772 } 773 else if (GET_CODE (xplus1) == UNSPEC) 774 { 775 /* Need offsettable address. */ 776 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) 777 return false; 778 779 return microblaze_classify_unspec (info, xplus1); 780 } 781 else if ((GET_CODE (xplus1) == SYMBOL_REF || 782 GET_CODE (xplus1) == LABEL_REF)) 783 { 784 if (flag_pic == 2 || microblaze_tls_symbol_p(xplus1)) 785 return false; 786 info->type = ADDRESS_SYMBOLIC; 787 info->symbol = xplus1; 788 info->symbol_type = SYMBOL_TYPE_GENERAL; 789 return true; 790 } 791 else if (GET_CODE (xplus1) == CONST) 792 { 793 rtx xconst0 = XEXP(xplus1, 0); 794 795 /* base + unspec. */ 796 if (GET_CODE (xconst0) == UNSPEC) 797 { 798 /* Need offsettable address. */ 799 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) 800 return false; 801 return microblaze_classify_unspec(info, xconst0); 802 } 803 804 /* for (plus x const_int) just look at x. */ 805 if (GET_CODE (xconst0) == PLUS 806 && GET_CODE (XEXP (xconst0, 1)) == CONST_INT 807 && (SMALL_INT (XEXP (xconst0, 1)) 808 || GET_CODE (XEXP (xconst0, 0)) == UNSPEC)) 809 { 810 /* Hold CONST_INT Value in offset in case of 811 UNSPEC + CONST_INT. */ 812 offset = XEXP (xconst0, 1); 813 814 /* This is ok as info->symbol is set to xplus1 the full 815 const-expression below. */ 816 xconst0 = XEXP (xconst0, 0); 817 } 818 819 if (GET_CODE (xconst0) == SYMBOL_REF 820 || GET_CODE (xconst0) == LABEL_REF) 821 { 822 if (flag_pic == 2 || microblaze_tls_symbol_p(xconst0)) 823 return false; 824 825 info->type = ADDRESS_SYMBOLIC; 826 info->symbol = xplus1; 827 info->symbol_type = SYMBOL_TYPE_GENERAL; 828 return true; 829 } 830 831 if (GET_CODE (xconst0) == UNSPEC && TARGET_PIC_DATA_TEXT_REL) 832 { 833 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) 834 return false; 835 836 info->offset = offset; 837 return microblaze_classify_unspec (info, xconst0); 838 } 839 840 /* Not base + symbol || base + UNSPEC. */ 841 return false; 842 843 } 844 else if (GET_CODE (xplus1) == REG 845 && microblaze_valid_index_register_p (xplus1, mode, 846 strict) 847 && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)) 848 { 849 /* Restrict larger than word-width modes from using an index register. */ 850 info->type = ADDRESS_REG_INDEX; 851 info->regB = xplus1; 852 return true; 853 } 854 } 855 break; 856 } 857 case CONST_INT: 858 { 859 info->regA = gen_raw_REG (mode, 0); 860 info->type = ADDRESS_CONST_INT; 861 info->offset = x; 862 return true; 863 } 864 case CONST: 865 case LABEL_REF: 866 case SYMBOL_REF: 867 { 868 info->type = ADDRESS_SYMBOLIC; 869 info->symbol_type = SYMBOL_TYPE_GENERAL; 870 info->symbol = x; 871 info->regA = gen_raw_REG (mode, get_base_reg (x)); 872 873 if (GET_CODE (x) == CONST) 874 { 875 if (GET_CODE (XEXP (x, 0)) == UNSPEC) 876 { 877 info->regA = gen_raw_REG (mode, 878 get_base_reg (XVECEXP (XEXP (x,0), 0, 0))); 879 return microblaze_classify_unspec (info, XEXP (x, 0)); 880 } 881 return !(flag_pic && pic_address_needs_scratch (x)); 882 } 883 884 /* Avoid error in print_operand_address in case UNSPEC 885 is removed from SYMBOL or LABEL REFS during optimization. */ 886 if ((GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) 887 && flag_pic && TARGET_PIC_DATA_TEXT_REL && strict == 2) 888 { 889 info->type = ADDRESS_SYMBOLIC_TXT_REL; 890 return true; 891 } 892 893 if (flag_pic == 2) 894 return false; 895 else if (microblaze_tls_symbol_p(x)) 896 return false; 897 898 return true; 899 } 900 901 case UNSPEC: 902 { 903 if (reload_in_progress) 904 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); 905 return microblaze_classify_unspec (info, x); 906 } 907 908 default: 909 return false; 910 } 911 912 return false; 913 } 914 915 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It 916 returns a nonzero value if X is a legitimate address for a memory 917 operand of the indicated MODE. STRICT is nonzero if this function 918 is called during reload. */ 919 920 bool 921 microblaze_legitimate_address_p (machine_mode mode, rtx x, bool strict) 922 { 923 struct microblaze_address_info addr; 924 925 return microblaze_classify_address (&addr, x, mode, strict); 926 } 927 928 bool 929 microblaze_constant_address_p (rtx x) 930 { 931 return ((GET_CODE (x) == LABEL_REF) || (GET_CODE (x) == SYMBOL_REF) 932 || GET_CODE (x) == CONST_INT 933 || (GET_CODE (x) == CONST 934 && ! (flag_pic && pic_address_needs_scratch (x)))); 935 } 936 937 int 938 microblaze_valid_pic_const (rtx x) 939 { 940 switch (GET_CODE (x)) 941 { 942 case CONST: 943 case CONST_INT: 944 case CONST_DOUBLE: 945 return true; 946 default: 947 return false; 948 } 949 } 950 951 int 952 microblaze_legitimate_pic_operand (rtx x) 953 { 954 if (flag_pic == 2 && (symbol_mentioned_p (x) || label_mentioned_p (x)) 955 && !(TARGET_PIC_DATA_TEXT_REL && call_insn_operand (x,VOIDmode))) 956 return 0; 957 958 if (microblaze_tls_referenced_p(x)) 959 return 0; 960 961 return 1; 962 } 963 964 /* Try machine-dependent ways of modifying an illegitimate address 965 to be legitimate. If we find one, return the new, valid address. 966 This is used from only one place: `memory_address' in explow.c. 967 968 OLDX is the address as it was before break_out_memory_refs was 969 called. In some cases it is useful to look at this to decide what 970 needs to be done. 971 972 It is always safe for this function to do nothing. It exists to 973 recognize opportunities to optimize the output. 974 975 For the MicroBlaze, transform: 976 977 memory(X + <large int>) 978 979 into: 980 981 Y = <large int> & ~0x7fff; 982 Z = X + Y 983 memory (Z + (<large int> & 0x7fff)); 984 985 This is for CSE to find several similar references, and only use one Z. 986 987 When PIC, convert addresses of the form memory (symbol+large int) to 988 memory (reg+large int). */ 989 990 static rtx 991 microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, 992 machine_mode mode ATTRIBUTE_UNUSED) 993 { 994 register rtx xinsn = x, result; 995 996 if (GET_CODE (xinsn) == CONST 997 && flag_pic && pic_address_needs_scratch (xinsn)) 998 { 999 rtx ptr_reg = gen_reg_rtx (Pmode); 1000 rtx constant = XEXP (XEXP (xinsn, 0), 1); 1001 1002 emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0)); 1003 1004 result = gen_rtx_PLUS (Pmode, ptr_reg, constant); 1005 if (SMALL_INT (constant)) 1006 return result; 1007 /* Otherwise we fall through so the code below will fix the 1008 constant. */ 1009 xinsn = result; 1010 } 1011 1012 if (GET_CODE (xinsn) == PLUS) 1013 { 1014 register rtx xplus0 = XEXP (xinsn, 0); 1015 register rtx xplus1 = XEXP (xinsn, 1); 1016 register enum rtx_code code0 = GET_CODE (xplus0); 1017 register enum rtx_code code1 = GET_CODE (xplus1); 1018 1019 if (code0 != REG && code1 == REG) 1020 { 1021 xplus0 = XEXP (xinsn, 1); 1022 xplus1 = XEXP (xinsn, 0); 1023 code0 = GET_CODE (xplus0); 1024 code1 = GET_CODE (xplus1); 1025 } 1026 1027 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0) 1028 && code1 == CONST_INT && !SMALL_INT (xplus1)) 1029 { 1030 rtx int_reg = gen_reg_rtx (Pmode); 1031 rtx ptr_reg = gen_reg_rtx (Pmode); 1032 1033 emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff)); 1034 1035 emit_insn (gen_rtx_SET (ptr_reg, 1036 gen_rtx_PLUS (Pmode, xplus0, int_reg))); 1037 1038 result = gen_rtx_PLUS (Pmode, ptr_reg, 1039 GEN_INT (INTVAL (xplus1) & 0x7fff)); 1040 return result; 1041 } 1042 1043 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)) 1044 { 1045 if (reload_in_progress) 1046 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); 1047 if (code1 == CONST) 1048 { 1049 xplus1 = XEXP (xplus1, 0); 1050 code1 = GET_CODE (xplus1); 1051 } 1052 if (code1 == SYMBOL_REF) 1053 { 1054 if (microblaze_tls_symbol_p(xplus1)) 1055 { 1056 rtx tls_ref, reg; 1057 reg = gen_reg_rtx (Pmode); 1058 1059 tls_ref = microblaze_legitimize_tls_address (xplus1, 1060 NULL_RTX); 1061 emit_move_insn (reg, tls_ref); 1062 1063 result = gen_rtx_PLUS (Pmode, xplus0, reg); 1064 1065 return result; 1066 } 1067 else if (flag_pic == 2) 1068 { 1069 if (!TARGET_PIC_DATA_TEXT_REL) 1070 { 1071 rtx pic_ref, reg; 1072 reg = gen_reg_rtx (Pmode); 1073 1074 pic_ref = gen_rtx_UNSPEC (Pmode, 1075 gen_rtvec (1, xplus1), 1076 UNSPEC_GOTOFF); 1077 pic_ref = gen_rtx_CONST (Pmode, pic_ref); 1078 pic_ref = gen_rtx_PLUS (Pmode, 1079 pic_offset_table_rtx, pic_ref); 1080 pic_ref = gen_const_mem (Pmode, pic_ref); 1081 emit_move_insn (reg, pic_ref); 1082 result = gen_rtx_PLUS (Pmode, xplus0, reg); 1083 return result; 1084 } 1085 else 1086 { 1087 rtx pic_ref, reg; 1088 reg = gen_reg_rtx (Pmode); 1089 pic_ref = gen_rtx_UNSPEC (Pmode, 1090 gen_rtvec (1, xplus1), 1091 UNSPEC_TEXT); 1092 pic_ref = gen_rtx_CONST (Pmode, pic_ref); 1093 emit_insn (gen_addsi3 (reg, 1094 pic_offset_table_rtx, xplus0)); 1095 result = gen_rtx_PLUS (Pmode, reg, pic_ref); 1096 return result; 1097 } 1098 } 1099 } 1100 } 1101 } 1102 1103 if (GET_CODE (xinsn) == SYMBOL_REF) 1104 { 1105 rtx reg; 1106 if (microblaze_tls_symbol_p(xinsn)) 1107 { 1108 reg = microblaze_legitimize_tls_address (xinsn, NULL_RTX); 1109 } 1110 else if (flag_pic == 2) 1111 { 1112 if (reload_in_progress) 1113 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); 1114 1115 if (!TARGET_PIC_DATA_TEXT_REL) 1116 { 1117 rtx pic_ref; 1118 1119 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF); 1120 pic_ref = gen_rtx_CONST (Pmode, pic_ref); 1121 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref); 1122 pic_ref = gen_const_mem (Pmode, pic_ref); 1123 reg = pic_ref; 1124 } 1125 else 1126 { 1127 rtx pic_ref; 1128 1129 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_TEXT); 1130 pic_ref = gen_rtx_CONST (Pmode, pic_ref); 1131 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref); 1132 reg = pic_ref; 1133 } 1134 } 1135 return reg; 1136 } 1137 1138 return x; 1139 } 1140 1141 /* Block Moves. */ 1142 1143 #define MAX_MOVE_REGS 8 1144 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD) 1145 1146 /* Emit straight-line code to move LENGTH bytes from SRC to DEST. 1147 Assume that the areas do not overlap. */ 1148 1149 static void 1150 microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length) 1151 { 1152 HOST_WIDE_INT offset, delta; 1153 unsigned HOST_WIDE_INT bits; 1154 int i; 1155 machine_mode mode; 1156 rtx *regs; 1157 1158 bits = BITS_PER_WORD; 1159 mode = int_mode_for_size (bits, 0).require (); 1160 delta = bits / BITS_PER_UNIT; 1161 1162 /* Allocate a buffer for the temporary registers. */ 1163 regs = XALLOCAVEC (rtx, length / delta); 1164 1165 /* Load as many BITS-sized chunks as possible. Use a normal load if 1166 the source has enough alignment, otherwise use left/right pairs. */ 1167 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++) 1168 { 1169 regs[i] = gen_reg_rtx (mode); 1170 emit_move_insn (regs[i], adjust_address (src, mode, offset)); 1171 } 1172 1173 /* Copy the chunks to the destination. */ 1174 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++) 1175 emit_move_insn (adjust_address (dest, mode, offset), regs[i]); 1176 1177 /* Mop up any left-over bytes. */ 1178 if (offset < length) 1179 { 1180 src = adjust_address (src, BLKmode, offset); 1181 dest = adjust_address (dest, BLKmode, offset); 1182 move_by_pieces (dest, src, length - offset, 1183 MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), RETURN_BEGIN); 1184 } 1185 } 1186 1187 /* Helper function for doing a loop-based block operation on memory 1188 reference MEM. Each iteration of the loop will operate on LENGTH 1189 bytes of MEM. 1190 1191 Create a new base register for use within the loop and point it to 1192 the start of MEM. Create a new memory reference that uses this 1193 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */ 1194 1195 static void 1196 microblaze_adjust_block_mem (rtx mem, HOST_WIDE_INT length, 1197 rtx * loop_reg, rtx * loop_mem) 1198 { 1199 *loop_reg = copy_addr_to_reg (XEXP (mem, 0)); 1200 1201 /* Although the new mem does not refer to a known location, 1202 it does keep up to LENGTH bytes of alignment. */ 1203 *loop_mem = change_address (mem, BLKmode, *loop_reg); 1204 set_mem_align (*loop_mem, 1205 MIN ((HOST_WIDE_INT) MEM_ALIGN (mem), 1206 length * BITS_PER_UNIT)); 1207 } 1208 1209 1210 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES 1211 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the 1212 memory regions do not overlap. */ 1213 1214 static void 1215 microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length) 1216 { 1217 rtx_code_label *label; 1218 rtx src_reg, dest_reg, final_src; 1219 HOST_WIDE_INT leftover; 1220 1221 leftover = length % MAX_MOVE_BYTES; 1222 length -= leftover; 1223 1224 /* Create registers and memory references for use within the loop. */ 1225 microblaze_adjust_block_mem (src, MAX_MOVE_BYTES, &src_reg, &src); 1226 microblaze_adjust_block_mem (dest, MAX_MOVE_BYTES, &dest_reg, &dest); 1227 1228 /* Calculate the value that SRC_REG should have after the last iteration 1229 of the loop. */ 1230 final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length), 1231 0, 0, OPTAB_WIDEN); 1232 1233 /* Emit the start of the loop. */ 1234 label = gen_label_rtx (); 1235 emit_label (label); 1236 1237 /* Emit the loop body. */ 1238 microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES); 1239 1240 /* Move on to the next block. */ 1241 emit_move_insn (src_reg, plus_constant (Pmode, src_reg, MAX_MOVE_BYTES)); 1242 emit_move_insn (dest_reg, plus_constant (Pmode, dest_reg, MAX_MOVE_BYTES)); 1243 1244 /* Emit the test & branch. */ 1245 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src), 1246 src_reg, final_src, label)); 1247 1248 /* Mop up any left-over bytes. */ 1249 if (leftover) 1250 microblaze_block_move_straight (dest, src, leftover); 1251 } 1252 1253 /* Expand a cpymemsi instruction. */ 1254 1255 bool 1256 microblaze_expand_block_move (rtx dest, rtx src, rtx length, rtx align_rtx) 1257 { 1258 1259 if (GET_CODE (length) == CONST_INT) 1260 { 1261 unsigned HOST_WIDE_INT bytes = UINTVAL (length); 1262 unsigned int align = UINTVAL (align_rtx); 1263 1264 if (align > UNITS_PER_WORD) 1265 { 1266 align = UNITS_PER_WORD; /* We can't do any better. */ 1267 } 1268 else if (align < UNITS_PER_WORD) 1269 { 1270 if (UINTVAL (length) <= MAX_MOVE_BYTES) 1271 { 1272 move_by_pieces (dest, src, bytes, align, RETURN_BEGIN); 1273 return true; 1274 } 1275 else 1276 return false; 1277 } 1278 1279 if (UINTVAL (length) <= 2 * MAX_MOVE_BYTES) 1280 { 1281 microblaze_block_move_straight (dest, src, UINTVAL (length)); 1282 return true; 1283 } 1284 else if (optimize) 1285 { 1286 microblaze_block_move_loop (dest, src, UINTVAL (length)); 1287 return true; 1288 } 1289 } 1290 return false; 1291 } 1292 1293 static bool 1294 microblaze_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED, 1295 int opno ATTRIBUTE_UNUSED, int *total, 1296 bool speed ATTRIBUTE_UNUSED) 1297 { 1298 int code = GET_CODE (x); 1299 1300 switch (code) 1301 { 1302 case MEM: 1303 { 1304 int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1; 1305 if (simple_memory_operand (x, mode)) 1306 *total = COSTS_N_INSNS (2 * num_words); 1307 else 1308 *total = COSTS_N_INSNS (2 * (2 * num_words)); 1309 1310 return true; 1311 } 1312 case NOT: 1313 { 1314 if (mode == DImode) 1315 { 1316 *total = COSTS_N_INSNS (2); 1317 } 1318 else 1319 *total = COSTS_N_INSNS (1); 1320 return false; 1321 } 1322 case AND: 1323 case IOR: 1324 case XOR: 1325 { 1326 if (mode == DImode) 1327 { 1328 *total = COSTS_N_INSNS (2); 1329 } 1330 else 1331 *total = COSTS_N_INSNS (1); 1332 1333 return false; 1334 } 1335 case ASHIFT: 1336 case ASHIFTRT: 1337 case LSHIFTRT: 1338 { 1339 if (TARGET_BARREL_SHIFT) 1340 { 1341 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") 1342 >= 0) 1343 *total = COSTS_N_INSNS (1); 1344 else 1345 *total = COSTS_N_INSNS (2); 1346 } 1347 else if (!TARGET_SOFT_MUL) 1348 *total = COSTS_N_INSNS (1); 1349 else if (GET_CODE (XEXP (x, 1)) == CONST_INT) 1350 { 1351 /* Add 1 to make shift slightly more expensive than add. */ 1352 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1; 1353 /* Reduce shift costs for special circumstances. */ 1354 if (optimize_size && INTVAL (XEXP (x, 1)) > 5) 1355 *total -= 2; 1356 if (!optimize_size && INTVAL (XEXP (x, 1)) > 17) 1357 *total -= 2; 1358 } 1359 else 1360 /* Double the worst cost of shifts when there is no barrel shifter and 1361 the shift amount is in a reg. */ 1362 *total = COSTS_N_INSNS (32 * 4); 1363 return true; 1364 } 1365 case PLUS: 1366 case MINUS: 1367 { 1368 if (mode == SFmode || mode == DFmode) 1369 { 1370 if (TARGET_HARD_FLOAT) 1371 *total = COSTS_N_INSNS (6); 1372 return true; 1373 } 1374 else if (mode == DImode) 1375 { 1376 *total = COSTS_N_INSNS (4); 1377 return true; 1378 } 1379 else 1380 { 1381 *total = COSTS_N_INSNS (1); 1382 return true; 1383 } 1384 1385 return false; 1386 } 1387 case NEG: 1388 { 1389 if (mode == DImode) 1390 *total = COSTS_N_INSNS (4); 1391 1392 return false; 1393 } 1394 case MULT: 1395 { 1396 if (mode == SFmode) 1397 { 1398 if (TARGET_HARD_FLOAT) 1399 *total = COSTS_N_INSNS (6); 1400 } 1401 else if (!TARGET_SOFT_MUL) 1402 { 1403 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") 1404 >= 0) 1405 *total = COSTS_N_INSNS (1); 1406 else 1407 *total = COSTS_N_INSNS (3); 1408 } 1409 else 1410 *total = COSTS_N_INSNS (10); 1411 return true; 1412 } 1413 case DIV: 1414 case UDIV: 1415 { 1416 if (mode == SFmode) 1417 { 1418 if (TARGET_HARD_FLOAT) 1419 *total = COSTS_N_INSNS (23); 1420 } 1421 return false; 1422 } 1423 case SIGN_EXTEND: 1424 { 1425 *total = COSTS_N_INSNS (1); 1426 return false; 1427 } 1428 case ZERO_EXTEND: 1429 { 1430 *total = COSTS_N_INSNS (1); 1431 return false; 1432 } 1433 } 1434 1435 return false; 1436 } 1437 1438 /* Return the number of instructions needed to load or store a value 1439 of mode MODE at X. Return 0 if X isn't valid for MODE. */ 1440 1441 static int 1442 microblaze_address_insns (rtx x, machine_mode mode) 1443 { 1444 struct microblaze_address_info addr; 1445 1446 if (microblaze_classify_address (&addr, x, mode, false)) 1447 { 1448 switch (addr.type) 1449 { 1450 case ADDRESS_REG: 1451 if (SMALL_INT (addr.offset)) 1452 return 1; 1453 else 1454 return 2; 1455 case ADDRESS_CONST_INT: 1456 if (SMALL_INT (x)) 1457 return 1; 1458 else 1459 return 2; 1460 case ADDRESS_REG_INDEX: 1461 return 1; 1462 case ADDRESS_SYMBOLIC: 1463 case ADDRESS_SYMBOLIC_TXT_REL: 1464 case ADDRESS_GOTOFF: 1465 return 2; 1466 case ADDRESS_TLS: 1467 switch (addr.tls_type) 1468 { 1469 case TLS_GD: 1470 return 2; 1471 case TLS_LDM: 1472 return 2; 1473 case TLS_DTPREL: 1474 return 1; 1475 default : 1476 abort(); 1477 } 1478 default: 1479 break; 1480 } 1481 } 1482 return 0; 1483 } 1484 1485 /* Provide the costs of an addressing mode that contains ADDR. 1486 If ADDR is not a valid address, its cost is irrelevant. */ 1487 static int 1488 microblaze_address_cost (rtx addr, machine_mode mode ATTRIBUTE_UNUSED, 1489 addr_space_t as ATTRIBUTE_UNUSED, 1490 bool speed ATTRIBUTE_UNUSED) 1491 { 1492 return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr))); 1493 } 1494 1495 /* Return nonzero if X is an address which needs a temporary register when 1496 reloaded while generating PIC code. */ 1497 1498 int 1499 pic_address_needs_scratch (rtx x) 1500 { 1501 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS) 1502 { 1503 rtx p0, p1; 1504 1505 p0 = XEXP (XEXP (x, 0), 0); 1506 p1 = XEXP (XEXP (x, 0), 1); 1507 1508 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF) 1509 && (GET_CODE (p1) == CONST_INT) 1510 && (flag_pic == 2 || microblaze_tls_symbol_p (p0) || !SMALL_INT (p1))) 1511 return 1; 1512 } 1513 return 0; 1514 } 1515 1516 /* Argument support functions. */ 1517 /* Initialize CUMULATIVE_ARGS for a function. */ 1518 1519 void 1520 init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype, 1521 rtx libname ATTRIBUTE_UNUSED) 1522 { 1523 static CUMULATIVE_ARGS zero_cum; 1524 tree param, next_param; 1525 1526 *cum = zero_cum; 1527 1528 /* Determine if this function has variable arguments. This is 1529 indicated by the last argument being 'void_type_mode' if there 1530 are no variable arguments. The standard MicroBlaze calling sequence 1531 passes all arguments in the general purpose registers in this case. */ 1532 1533 for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0; 1534 param != 0; param = next_param) 1535 { 1536 next_param = TREE_CHAIN (param); 1537 if (next_param == 0 && TREE_VALUE (param) != void_type_node) 1538 cum->gp_reg_found = 1; 1539 } 1540 } 1541 1542 /* Advance the argument to the next argument position. */ 1543 1544 static void 1545 microblaze_function_arg_advance (cumulative_args_t cum_v, 1546 const function_arg_info &arg) 1547 { 1548 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); 1549 1550 cum->arg_number++; 1551 switch (arg.mode) 1552 { 1553 case E_VOIDmode: 1554 break; 1555 1556 default: 1557 gcc_assert (GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_INT 1558 || GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_FLOAT); 1559 1560 cum->gp_reg_found = 1; 1561 cum->arg_words += ((GET_MODE_SIZE (arg.mode) + UNITS_PER_WORD - 1) 1562 / UNITS_PER_WORD); 1563 break; 1564 1565 case E_BLKmode: 1566 cum->gp_reg_found = 1; 1567 cum->arg_words += ((int_size_in_bytes (arg.type) + UNITS_PER_WORD - 1) 1568 / UNITS_PER_WORD); 1569 break; 1570 1571 case E_SFmode: 1572 cum->arg_words++; 1573 if (!cum->gp_reg_found && cum->arg_number <= 2) 1574 cum->fp_code += 1 << ((cum->arg_number - 1) * 2); 1575 break; 1576 1577 case E_DFmode: 1578 cum->arg_words += 2; 1579 if (!cum->gp_reg_found && cum->arg_number <= 2) 1580 cum->fp_code += 2 << ((cum->arg_number - 1) * 2); 1581 break; 1582 1583 case E_DImode: 1584 cum->gp_reg_found = 1; 1585 cum->arg_words += 2; 1586 break; 1587 1588 case E_QImode: 1589 case E_HImode: 1590 case E_SImode: 1591 case E_TImode: 1592 cum->gp_reg_found = 1; 1593 cum->arg_words++; 1594 break; 1595 } 1596 } 1597 1598 /* Return an RTL expression containing the register for the given argument 1599 or 0 if the argument is to be passed on the stack. */ 1600 1601 static rtx 1602 microblaze_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) 1603 { 1604 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); 1605 1606 rtx ret; 1607 int regbase = -1; 1608 int *arg_words = &cum->arg_words; 1609 1610 cum->last_arg_fp = 0; 1611 switch (arg.mode) 1612 { 1613 case E_SFmode: 1614 case E_DFmode: 1615 case E_VOIDmode: 1616 case E_QImode: 1617 case E_HImode: 1618 case E_SImode: 1619 case E_DImode: 1620 case E_TImode: 1621 regbase = GP_ARG_FIRST; 1622 break; 1623 default: 1624 gcc_assert (GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_INT 1625 || GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_FLOAT); 1626 /* FALLTHRU */ 1627 case E_BLKmode: 1628 regbase = GP_ARG_FIRST; 1629 break; 1630 } 1631 1632 if (*arg_words >= MAX_ARGS_IN_REGISTERS) 1633 ret = 0; 1634 else 1635 { 1636 gcc_assert (regbase != -1); 1637 1638 ret = gen_rtx_REG (arg.mode, regbase + *arg_words); 1639 } 1640 1641 if (arg.end_marker_p ()) 1642 { 1643 if (cum->num_adjusts > 0) 1644 ret = gen_rtx_PARALLEL ((machine_mode) cum->fp_code, 1645 gen_rtvec_v (cum->num_adjusts, cum->adjust)); 1646 } 1647 1648 return ret; 1649 } 1650 1651 /* Return number of bytes of argument to put in registers. */ 1652 static int 1653 function_arg_partial_bytes (cumulative_args_t cum_v, 1654 const function_arg_info &arg) 1655 { 1656 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); 1657 1658 if ((arg.mode == BLKmode 1659 || GET_MODE_CLASS (arg.mode) != MODE_COMPLEX_INT 1660 || GET_MODE_CLASS (arg.mode) != MODE_COMPLEX_FLOAT) 1661 && cum->arg_words < MAX_ARGS_IN_REGISTERS) 1662 { 1663 int words = ((arg.promoted_size_in_bytes () + UNITS_PER_WORD - 1) 1664 / UNITS_PER_WORD); 1665 if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS) 1666 return 0; /* structure fits in registers */ 1667 1668 return (MAX_ARGS_IN_REGISTERS - cum->arg_words) * UNITS_PER_WORD; 1669 } 1670 1671 else if (arg.mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1) 1672 return UNITS_PER_WORD; 1673 1674 return 0; 1675 } 1676 1677 /* Convert a version number of the form "vX.YY.Z" to an integer encoding 1678 for easier range comparison. */ 1679 static int 1680 microblaze_version_to_int (const char *version) 1681 { 1682 const char *p, *v; 1683 const char *tmpl = "vXX.YY.Z"; 1684 int iver = 0; 1685 1686 p = version; 1687 v = tmpl; 1688 1689 while (*p) 1690 { 1691 if (*v == 'X') 1692 { /* Looking for major */ 1693 if (*p == '.') 1694 { 1695 v++; 1696 } 1697 else 1698 { 1699 if (!(*p >= '0' && *p <= '9')) 1700 return -1; 1701 iver += (int) (*p - '0'); 1702 iver *= 10; 1703 } 1704 } 1705 else if (*v == 'Y') 1706 { /* Looking for minor */ 1707 if (!(*p >= '0' && *p <= '9')) 1708 return -1; 1709 iver += (int) (*p - '0'); 1710 iver *= 10; 1711 } 1712 else if (*v == 'Z') 1713 { /* Looking for compat */ 1714 if (!(*p >= 'a' && *p <= 'z')) 1715 return -1; 1716 iver *= 10; 1717 iver += (int) (*p - 'a'); 1718 } 1719 else 1720 { 1721 if (*p != *v) 1722 return -1; 1723 } 1724 1725 v++; 1726 p++; 1727 } 1728 1729 if (*p) 1730 return -1; 1731 1732 return iver; 1733 } 1734 1735 1736 static void 1737 microblaze_option_override (void) 1738 { 1739 register int i, start; 1740 register int regno; 1741 register machine_mode mode; 1742 int ver; 1743 1744 microblaze_section_threshold = (global_options_set.x_g_switch_value 1745 ? g_switch_value 1746 : MICROBLAZE_DEFAULT_GVALUE); 1747 1748 if (flag_pic) 1749 { 1750 /* Make sure it's 2, we only support one kind of PIC. */ 1751 flag_pic = 2; 1752 if (!TARGET_SUPPORTS_PIC) 1753 { 1754 error ("%<-fPIC%>/%<-fpic%> not supported for this target"); 1755 /* Clear it to avoid further errors. */ 1756 flag_pic = 0; 1757 } 1758 } 1759 1760 /* Check the MicroBlaze CPU version for any special action to be done. */ 1761 if (microblaze_select_cpu == NULL) 1762 microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU; 1763 ver = microblaze_version_to_int (microblaze_select_cpu); 1764 if (ver == -1) 1765 { 1766 error ("%qs is an invalid argument to %<-mcpu=%>", microblaze_select_cpu); 1767 } 1768 1769 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v3.00.a"); 1770 if (ver < 0) 1771 { 1772 /* No hardware exceptions in earlier versions. So no worries. */ 1773 #if 0 1774 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY); 1775 #endif 1776 microblaze_no_unsafe_delay = 0; 1777 microblaze_pipe = MICROBLAZE_PIPE_3; 1778 } 1779 else if (ver == 0 1780 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b") 1781 == 0)) 1782 { 1783 #if 0 1784 microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY); 1785 #endif 1786 microblaze_no_unsafe_delay = 1; 1787 microblaze_pipe = MICROBLAZE_PIPE_3; 1788 } 1789 else 1790 { 1791 /* We agree to use 5 pipe-stage model even on area optimized 3 1792 pipe-stage variants. */ 1793 #if 0 1794 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY); 1795 #endif 1796 microblaze_no_unsafe_delay = 0; 1797 microblaze_pipe = MICROBLAZE_PIPE_5; 1798 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0 1799 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, 1800 "v5.00.b") == 0 1801 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, 1802 "v5.00.c") == 0) 1803 { 1804 /* Pattern compares are to be turned on by default only when 1805 compiling for MB v5.00.'z'. */ 1806 target_flags |= MASK_PATTERN_COMPARE; 1807 } 1808 } 1809 1810 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a"); 1811 if (ver < 0) 1812 { 1813 if (TARGET_MULTIPLY_HIGH) 1814 warning (0, 1815 "%<-mxl-multiply-high%> can be used only with " 1816 "%<-mcpu=v6.00.a%> or greater"); 1817 } 1818 1819 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.10.a"); 1820 microblaze_has_clz = 1; 1821 if (ver < 0) 1822 { 1823 /* MicroBlaze prior to 8.10.a didn't have clz. */ 1824 microblaze_has_clz = 0; 1825 } 1826 1827 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */ 1828 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.30.a"); 1829 if (ver < 0) 1830 { 1831 if (TARGET_REORDER == 1) 1832 warning (0, "%<-mxl-reorder%> can be used only with " 1833 "%<-mcpu=v8.30.a%> or greater"); 1834 TARGET_REORDER = 0; 1835 } 1836 else if ((ver == 0) && !TARGET_PATTERN_COMPARE) 1837 { 1838 if (TARGET_REORDER == 1) 1839 warning (0, "%<-mxl-reorder%> requires %<-mxl-pattern-compare%> for " 1840 "%<-mcpu=v8.30.a%>"); 1841 TARGET_REORDER = 0; 1842 } 1843 1844 if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL) 1845 error ("%<-mxl-multiply-high%> requires %<-mno-xl-soft-mul%>"); 1846 1847 /* Always use DFA scheduler. */ 1848 microblaze_sched_use_dfa = 1; 1849 1850 #if 0 1851 microblaze_abicalls = MICROBLAZE_ABICALLS_NO; 1852 #endif 1853 1854 /* Initialize the high, low values for legit floating point constants. */ 1855 real_maxval (&dfhigh, 0, DFmode); 1856 real_maxval (&dflow, 1, DFmode); 1857 real_maxval (&sfhigh, 0, SFmode); 1858 real_maxval (&sflow, 1, SFmode); 1859 1860 microblaze_print_operand_punct['?'] = 1; 1861 microblaze_print_operand_punct['#'] = 1; 1862 microblaze_print_operand_punct['&'] = 1; 1863 microblaze_print_operand_punct['!'] = 1; 1864 microblaze_print_operand_punct['*'] = 1; 1865 microblaze_print_operand_punct['@'] = 1; 1866 microblaze_print_operand_punct['.'] = 1; 1867 microblaze_print_operand_punct['('] = 1; 1868 microblaze_print_operand_punct[')'] = 1; 1869 microblaze_print_operand_punct['['] = 1; 1870 microblaze_print_operand_punct[']'] = 1; 1871 microblaze_print_operand_punct['<'] = 1; 1872 microblaze_print_operand_punct['>'] = 1; 1873 microblaze_print_operand_punct['{'] = 1; 1874 microblaze_print_operand_punct['}'] = 1; 1875 microblaze_print_operand_punct['^'] = 1; 1876 microblaze_print_operand_punct['$'] = 1; 1877 microblaze_print_operand_punct['+'] = 1; 1878 1879 /* Set up array to map GCC register number to debug register number. 1880 Ignore the special purpose register numbers. */ 1881 1882 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 1883 microblaze_dbx_regno[i] = -1; 1884 1885 start = GP_DBX_FIRST - GP_REG_FIRST; 1886 for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++) 1887 microblaze_dbx_regno[i] = i + start; 1888 1889 /* Set up array giving whether a given register can hold a given mode. */ 1890 1891 for (mode = VOIDmode; 1892 mode != MAX_MACHINE_MODE; mode = (machine_mode) ((int) mode + 1)) 1893 { 1894 register int size = GET_MODE_SIZE (mode); 1895 1896 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) 1897 { 1898 register int ok; 1899 1900 if (mode == CCmode) 1901 { 1902 ok = (ST_REG_P (regno) || GP_REG_P (regno)); 1903 } 1904 else if (GP_REG_P (regno)) 1905 ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD); 1906 else 1907 ok = 0; 1908 1909 microblaze_hard_regno_mode_ok_p[(int) mode][regno] = ok; 1910 } 1911 } 1912 } 1913 1914 /* Implement TARGET_HARD_REGNO_MODE_OK. In 32 bit mode, require that 1915 DImode and DFmode be in even registers. For DImode, this makes some 1916 of the insns easier to write, since you don't have to worry about a 1917 DImode value in registers 3 & 4, producing a result in 4 & 5. 1918 1919 To make the code simpler, the hook now just references an 1920 array built in override_options. */ 1921 1922 static bool 1923 microblaze_hard_regno_mode_ok (unsigned int regno, machine_mode mode) 1924 { 1925 return microblaze_hard_regno_mode_ok_p[mode][regno]; 1926 } 1927 1928 /* Implement TARGET_MODES_TIEABLE_P. */ 1929 1930 static bool 1931 microblaze_modes_tieable_p (machine_mode mode1, machine_mode mode2) 1932 { 1933 return ((GET_MODE_CLASS (mode1) == MODE_FLOAT 1934 || GET_MODE_CLASS (mode1) == MODE_COMPLEX_FLOAT) 1935 == (GET_MODE_CLASS (mode2) == MODE_FLOAT 1936 || GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT)); 1937 } 1938 1939 /* Return true if FUNC is an interrupt function as specified 1940 by the "interrupt_handler" attribute. */ 1941 1942 static int 1943 microblaze_interrupt_function_p (tree func) 1944 { 1945 tree a; 1946 1947 if (TREE_CODE (func) != FUNCTION_DECL) 1948 return 0; 1949 1950 a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func)); 1951 return a != NULL_TREE; 1952 } 1953 1954 static int 1955 microblaze_fast_interrupt_function_p (tree func) 1956 { 1957 tree a; 1958 1959 if (TREE_CODE (func) != FUNCTION_DECL) 1960 return 0; 1961 1962 a = lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func)); 1963 return a != NULL_TREE; 1964 } 1965 int 1966 microblaze_break_function_p (tree func) 1967 { 1968 tree a; 1969 if (!func) 1970 return 0; 1971 if (TREE_CODE (func) != FUNCTION_DECL) 1972 return 0; 1973 1974 a = lookup_attribute ("break_handler", DECL_ATTRIBUTES (func)); 1975 return a != NULL_TREE; 1976 } 1977 /* Return true if FUNC is an interrupt function which uses 1978 normal return, indicated by the "save_volatiles" attribute. */ 1979 1980 static int 1981 microblaze_save_volatiles (tree func) 1982 { 1983 tree a; 1984 1985 if (TREE_CODE (func) != FUNCTION_DECL) 1986 return 0; 1987 1988 a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func)); 1989 return a != NULL_TREE; 1990 } 1991 1992 /* Return whether function is tagged with 'interrupt_handler' 1993 or 'fast_interrupt' attribute. Return true if function 1994 should use return from interrupt rather than normal 1995 function return. */ 1996 int 1997 microblaze_is_interrupt_variant (void) 1998 { 1999 return (interrupt_handler || fast_interrupt); 2000 } 2001 int 2002 microblaze_is_break_handler (void) 2003 { 2004 return break_handler; 2005 } 2006 2007 /* Determine of register must be saved/restored in call. */ 2008 static int 2009 microblaze_must_save_register (int regno) 2010 { 2011 if (pic_offset_table_rtx && 2012 (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno)) 2013 return 1; 2014 2015 if (df_regs_ever_live_p (regno) && !call_used_or_fixed_reg_p (regno)) 2016 return 1; 2017 2018 if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM)) 2019 return 1; 2020 2021 if (crtl->calls_eh_return 2022 && regno == MB_ABI_SUB_RETURN_ADDR_REGNUM) 2023 return 1; 2024 2025 if (!crtl->is_leaf) 2026 { 2027 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM) 2028 return 1; 2029 if ((microblaze_is_interrupt_variant () || save_volatiles) && 2030 (regno >= 3 && regno <= 12)) 2031 return 1; 2032 } 2033 2034 if (microblaze_is_interrupt_variant ()) 2035 { 2036 if (df_regs_ever_live_p (regno) 2037 || regno == MB_ABI_MSR_SAVE_REG 2038 || ((interrupt_handler || fast_interrupt) 2039 && (regno == MB_ABI_ASM_TEMP_REGNUM 2040 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM))) 2041 return 1; 2042 } 2043 2044 if (save_volatiles) 2045 { 2046 if (df_regs_ever_live_p (regno) 2047 || regno == MB_ABI_ASM_TEMP_REGNUM 2048 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM) 2049 return 1; 2050 } 2051 2052 if (crtl->calls_eh_return 2053 && (regno == EH_RETURN_DATA_REGNO (0) 2054 || regno == EH_RETURN_DATA_REGNO (1))) 2055 return 1; 2056 2057 return 0; 2058 } 2059 2060 /* Return the bytes needed to compute the frame pointer from the current 2061 stack pointer. 2062 2063 MicroBlaze stack frames look like: 2064 2065 2066 2067 Before call After call 2068 +-----------------------+ +-----------------------+ 2069 high | | | | 2070 mem. | local variables, | | local variables, | 2071 | callee saved and | | callee saved and | 2072 | temps | | temps | 2073 +-----------------------+ +-----------------------+ 2074 | arguments for called | | arguments for called | 2075 | subroutines | | subroutines | 2076 | (optional) | | (optional) | 2077 +-----------------------+ +-----------------------+ 2078 | Link register | | Link register | 2079 SP->| | | | 2080 +-----------------------+ +-----------------------+ 2081 | | 2082 | local variables, | 2083 | callee saved and | 2084 | temps | 2085 +-----------------------+ 2086 | MSR (optional if, | 2087 | interrupt handler) | 2088 +-----------------------+ 2089 | | 2090 | alloca allocations | 2091 | | 2092 +-----------------------+ 2093 | | 2094 | arguments for called | 2095 | subroutines | 2096 | (optional) | 2097 | | 2098 +-----------------------+ 2099 | Link register | 2100 low FP,SP->| | 2101 memory +-----------------------+ 2102 2103 */ 2104 2105 static HOST_WIDE_INT 2106 compute_frame_size (HOST_WIDE_INT size) 2107 { 2108 int regno; 2109 HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */ 2110 HOST_WIDE_INT var_size; /* # bytes that local variables take up. */ 2111 HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */ 2112 int link_debug_size; /* # bytes for link register. */ 2113 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */ 2114 long mask; /* mask of saved gp registers. */ 2115 2116 interrupt_handler = 2117 microblaze_interrupt_function_p (current_function_decl); 2118 break_handler = 2119 microblaze_break_function_p (current_function_decl); 2120 2121 fast_interrupt = 2122 microblaze_fast_interrupt_function_p (current_function_decl); 2123 save_volatiles = microblaze_save_volatiles (current_function_decl); 2124 if (break_handler) 2125 interrupt_handler = break_handler; 2126 2127 gp_reg_size = 0; 2128 mask = 0; 2129 var_size = size; 2130 args_size = crtl->outgoing_args_size; 2131 2132 if ((args_size == 0) && cfun->calls_alloca) 2133 args_size = NUM_OF_ARGS * UNITS_PER_WORD; 2134 2135 total_size = var_size + args_size; 2136 2137 if (flag_pic == 2 && !TARGET_PIC_DATA_TEXT_REL) 2138 /* force setting GOT. */ 2139 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true); 2140 2141 /* Calculate space needed for gp registers. */ 2142 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) 2143 { 2144 if (microblaze_must_save_register (regno)) 2145 { 2146 2147 if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM) 2148 /* Don't account for link register. It is accounted specially below. */ 2149 gp_reg_size += GET_MODE_SIZE (SImode); 2150 2151 mask |= (1L << (regno - GP_REG_FIRST)); 2152 } 2153 } 2154 2155 total_size += gp_reg_size; 2156 2157 /* Add 4 bytes for MSR. */ 2158 if (microblaze_is_interrupt_variant ()) 2159 total_size += 4; 2160 2161 /* No space to be allocated for link register in leaf functions with no other 2162 stack requirements. */ 2163 if (total_size == 0 && crtl->is_leaf) 2164 link_debug_size = 0; 2165 else 2166 link_debug_size = UNITS_PER_WORD; 2167 2168 total_size += link_debug_size; 2169 2170 /* Save other computed information. */ 2171 current_frame_info.total_size = total_size; 2172 current_frame_info.var_size = var_size; 2173 current_frame_info.args_size = args_size; 2174 current_frame_info.gp_reg_size = gp_reg_size; 2175 current_frame_info.mask = mask; 2176 current_frame_info.initialized = reload_completed; 2177 current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD; 2178 current_frame_info.link_debug_size = link_debug_size; 2179 2180 if (mask) 2181 /* Offset from which to callee-save GP regs. */ 2182 current_frame_info.gp_offset = (total_size - gp_reg_size); 2183 else 2184 current_frame_info.gp_offset = 0; 2185 2186 /* Ok, we're done. */ 2187 return total_size; 2188 } 2189 2190 /* Make sure that we're not trying to eliminate to the wrong hard frame 2191 pointer. */ 2192 2193 static bool 2194 microblaze_can_eliminate (const int from, const int to) 2195 { 2196 return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p()) 2197 || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p()) 2198 || (from != RETURN_ADDRESS_POINTER_REGNUM 2199 && (to == HARD_FRAME_POINTER_REGNUM 2200 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed)))); 2201 } 2202 2203 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame 2204 pointer or argument pointer or the return address pointer. TO is either 2205 the stack pointer or hard frame pointer. */ 2206 2207 HOST_WIDE_INT 2208 microblaze_initial_elimination_offset (int from, int to) 2209 { 2210 HOST_WIDE_INT offset; 2211 2212 switch (from) 2213 { 2214 case FRAME_POINTER_REGNUM: 2215 offset = 0; 2216 break; 2217 case ARG_POINTER_REGNUM: 2218 if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM) 2219 offset = compute_frame_size (get_frame_size ()); 2220 else 2221 gcc_unreachable (); 2222 break; 2223 case RETURN_ADDRESS_POINTER_REGNUM: 2224 if (crtl->is_leaf) 2225 offset = 0; 2226 else 2227 offset = current_frame_info.gp_offset + 2228 ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT))); 2229 break; 2230 default: 2231 gcc_unreachable (); 2232 } 2233 return offset; 2234 } 2235 2236 /* Print operands using format code. 2237 2238 The MicroBlaze specific codes are: 2239 2240 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x", 2241 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x", 2242 'F' op is CONST_DOUBLE, print 32 bits in hex, 2243 'd' output integer constant in decimal, 2244 'z' if the operand is 0, use $0 instead of normal operand. 2245 'D' print second register of double-word register operand. 2246 'L' print low-order register of double-word register operand. 2247 'M' print high-order register of double-word register operand. 2248 'C' print part of opcode for a branch condition. 2249 'N' print part of opcode for a branch condition, inverted. 2250 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch). 2251 'B' print 'z' for EQ, 'n' for NE 2252 'b' print 'n' for EQ, 'z' for NE 2253 'T' print 'f' for EQ, 't' for NE 2254 't' print 't' for EQ, 'f' for NE 2255 'm' Print 1<<operand. 2256 'i' Print 'i' if MEM operand has immediate value 2257 'y' Print 'y' if MEM operand is single register 2258 'o' Print operand address+4 2259 '?' Print 'd' if we use a branch with delay slot instead of normal branch. 2260 'h' Print high word of const_double (int or float) value as hex 2261 'j' Print low word of const_double (int or float) value as hex 2262 's' Print -1 if operand is negative, 0 if positive (sign extend) 2263 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM). 2264 '#' Print nop if the delay slot of a branch is not filled. 2265 */ 2266 2267 void 2268 print_operand (FILE * file, rtx op, int letter) 2269 { 2270 register enum rtx_code code; 2271 2272 if (PRINT_OPERAND_PUNCT_VALID_P (letter)) 2273 { 2274 switch (letter) 2275 { 2276 case '?': 2277 /* Conditionally add a 'd' to indicate filled delay slot. */ 2278 if (final_sequence != NULL) 2279 fputs ("d", file); 2280 break; 2281 2282 case '#': 2283 /* Conditionally add a nop in unfilled delay slot. */ 2284 if (final_sequence == NULL) 2285 fputs ("nop\t\t# Unfilled delay slot\n", file); 2286 break; 2287 2288 case '@': 2289 fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file); 2290 break; 2291 2292 default: 2293 output_operand_lossage ("unknown punctuation '%c'", letter); 2294 break; 2295 } 2296 2297 return; 2298 } 2299 2300 if (!op) 2301 { 2302 output_operand_lossage ("null pointer"); 2303 return; 2304 } 2305 2306 code = GET_CODE (op); 2307 2308 if (code == SIGN_EXTEND) 2309 op = XEXP (op, 0), code = GET_CODE (op); 2310 2311 if (letter == 'C') 2312 switch (code) 2313 { 2314 case EQ: 2315 fputs ("eq", file); 2316 break; 2317 case NE: 2318 fputs ("ne", file); 2319 break; 2320 case GT: 2321 case GTU: 2322 fputs ("gt", file); 2323 break; 2324 case GE: 2325 case GEU: 2326 fputs ("ge", file); 2327 break; 2328 case LT: 2329 case LTU: 2330 fputs ("lt", file); 2331 break; 2332 case LE: 2333 case LEU: 2334 fputs ("le", file); 2335 break; 2336 default: 2337 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op); 2338 } 2339 2340 else if (letter == 'N') 2341 switch (code) 2342 { 2343 case EQ: 2344 fputs ("ne", file); 2345 break; 2346 case NE: 2347 fputs ("eq", file); 2348 break; 2349 case GT: 2350 case GTU: 2351 fputs ("le", file); 2352 break; 2353 case GE: 2354 case GEU: 2355 fputs ("lt", file); 2356 break; 2357 case LT: 2358 case LTU: 2359 fputs ("ge", file); 2360 break; 2361 case LE: 2362 case LEU: 2363 fputs ("gt", file); 2364 break; 2365 default: 2366 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op); 2367 } 2368 2369 else if (letter == 'S') 2370 { 2371 char buffer[100]; 2372 2373 ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op)); 2374 assemble_name (file, buffer); 2375 } 2376 2377 /* Print 'i' for memory operands which have immediate values. */ 2378 else if (letter == 'i') 2379 { 2380 if (code == MEM) 2381 { 2382 struct microblaze_address_info info; 2383 2384 if (!microblaze_classify_address 2385 (&info, XEXP (op, 0), GET_MODE (op), 1)) 2386 fatal_insn ("insn contains an invalid address !", op); 2387 2388 switch (info.type) 2389 { 2390 case ADDRESS_REG: 2391 case ADDRESS_CONST_INT: 2392 case ADDRESS_SYMBOLIC: 2393 case ADDRESS_SYMBOLIC_TXT_REL: 2394 case ADDRESS_GOTOFF: 2395 case ADDRESS_TLS: 2396 fputs ("i", file); 2397 break; 2398 case ADDRESS_REG_INDEX: 2399 break; 2400 case ADDRESS_INVALID: 2401 case ADDRESS_PLT: 2402 fatal_insn ("invalid address", op); 2403 } 2404 } 2405 } 2406 2407 else if (code == REG || code == SUBREG) 2408 { 2409 register int regnum; 2410 2411 if (code == REG) 2412 regnum = REGNO (op); 2413 else 2414 regnum = true_regnum (op); 2415 2416 if ((letter == 'M' && !WORDS_BIG_ENDIAN) 2417 || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D') 2418 regnum++; 2419 2420 fprintf (file, "%s", reg_names[regnum]); 2421 } 2422 2423 else if (code == MEM) 2424 if (letter == 'o') 2425 { 2426 rtx op4 = adjust_address (op, GET_MODE (op), 4); 2427 output_address (GET_MODE (op), XEXP (op4, 0)); 2428 } 2429 else if (letter == 'y') 2430 { 2431 rtx mem_reg = XEXP (op, 0); 2432 if (GET_CODE (mem_reg) == REG) 2433 { 2434 register int regnum = REGNO (mem_reg); 2435 fprintf (file, "%s", reg_names[regnum]); 2436 } 2437 } 2438 else 2439 output_address (GET_MODE (op), XEXP (op, 0)); 2440 2441 else if (letter == 'h' || letter == 'j') 2442 { 2443 long val[2]; 2444 if (code == CONST_DOUBLE) 2445 { 2446 if (GET_MODE (op) == DFmode) 2447 REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op), val); 2448 else 2449 { 2450 val[0] = CONST_DOUBLE_HIGH (op); 2451 val[1] = CONST_DOUBLE_LOW (op); 2452 } 2453 } 2454 else if (code == CONST_INT) 2455 { 2456 val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32; 2457 val[1] = INTVAL (op) & 0x00000000ffffffffLL; 2458 if (val[0] == 0 && val[1] < 0) 2459 val[0] = -1; 2460 2461 } 2462 fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]); 2463 } 2464 else if (code == CONST_DOUBLE) 2465 { 2466 if (letter == 'F') 2467 { 2468 unsigned long value_long; 2469 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op), 2470 value_long); 2471 fprintf (file, "0x%lx", value_long); 2472 } 2473 else 2474 { 2475 char s[60]; 2476 real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1); 2477 fputs (s, file); 2478 } 2479 } 2480 2481 else if (code == UNSPEC) 2482 { 2483 print_operand_address (file, op); 2484 } 2485 2486 else if (letter == 'x' && GET_CODE (op) == CONST_INT) 2487 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op)); 2488 2489 else if (letter == 'X' && GET_CODE (op) == CONST_INT) 2490 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op)); 2491 2492 else if (letter == 'd' && GET_CODE (op) == CONST_INT) 2493 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op))); 2494 2495 else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0) 2496 fputs (reg_names[GP_REG_FIRST], file); 2497 2498 else if (letter == 's' && GET_CODE (op) == CONST_INT) 2499 if (INTVAL (op) < 0) 2500 fputs ("-1", file); 2501 else 2502 fputs ("0", file); 2503 2504 else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's') 2505 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter); 2506 2507 else if (letter == 'B') 2508 fputs (code == EQ ? "z" : "n", file); 2509 else if (letter == 'b') 2510 fputs (code == EQ ? "n" : "z", file); 2511 else if (letter == 'T') 2512 fputs (code == EQ ? "f" : "t", file); 2513 else if (letter == 't') 2514 fputs (code == EQ ? "t" : "f", file); 2515 2516 else if (code == CONST 2517 && ((GET_CODE (XEXP (op, 0)) == REG) 2518 || (GET_CODE (XEXP (op, 0)) == UNSPEC))) 2519 { 2520 print_operand (file, XEXP (op, 0), letter); 2521 } 2522 else if (code == CONST 2523 && (GET_CODE (XEXP (op, 0)) == PLUS) 2524 && (GET_CODE (XEXP (XEXP (op, 0), 0)) == REG) 2525 && (GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST)) 2526 { 2527 print_operand_address (file, XEXP (op, 0)); 2528 } 2529 else if (letter == 'm') 2530 fprintf (file, "%ld", (1L << INTVAL (op))); 2531 else 2532 output_addr_const (file, op); 2533 } 2534 2535 /* A C compound statement to output to stdio stream STREAM the 2536 assembler syntax for an instruction operand that is a memory 2537 reference whose address is ADDR. ADDR is an RTL expression. 2538 2539 Possible address classifications and output formats are, 2540 2541 ADDRESS_REG "%0, r0" 2542 2543 ADDRESS_REG with non-zero "%0, <addr_const>" 2544 offset 2545 2546 ADDRESS_REG_INDEX "rA, RB" 2547 (if rA is r0, rA and rB are swapped) 2548 2549 ADDRESS_CONST_INT "r0, <addr_const>" 2550 2551 ADDRESS_SYMBOLIC "rBase, <addr_const>" 2552 (rBase is a base register suitable for the 2553 symbol's type) 2554 */ 2555 2556 void 2557 print_operand_address (FILE * file, rtx addr) 2558 { 2559 struct microblaze_address_info info; 2560 enum microblaze_address_type type; 2561 if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 2)) 2562 fatal_insn ("insn contains an invalid address !", addr); 2563 2564 type = info.type; 2565 switch (info.type) 2566 { 2567 case ADDRESS_REG: 2568 fprintf (file, "%s,", reg_names[REGNO (info.regA)]); 2569 output_addr_const (file, info.offset); 2570 break; 2571 case ADDRESS_REG_INDEX: 2572 if (REGNO (info.regA) == 0) 2573 /* Make rB == r0 instead of rA == r0. This helps reduce read port 2574 congestion. */ 2575 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)], 2576 reg_names[REGNO (info.regA)]); 2577 else if (REGNO (info.regB) != 0) 2578 /* This is a silly swap to help Dhrystone. */ 2579 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)], 2580 reg_names[REGNO (info.regA)]); 2581 break; 2582 case ADDRESS_CONST_INT: 2583 fprintf (file, "%s,", reg_names[REGNO (info.regA)]); 2584 output_addr_const (file, info.offset); 2585 break; 2586 case ADDRESS_SYMBOLIC: 2587 case ADDRESS_SYMBOLIC_TXT_REL: 2588 case ADDRESS_GOTOFF: 2589 case ADDRESS_PLT: 2590 case ADDRESS_TLS: 2591 if (info.regA) 2592 fprintf (file, "%s,", reg_names[REGNO (info.regA)]); 2593 output_addr_const (file, info.symbol); 2594 if (type == ADDRESS_GOTOFF) 2595 { 2596 fputs ("@GOT", file); 2597 } 2598 else if (type == ADDRESS_PLT) 2599 { 2600 fputs ("@PLT", file); 2601 } 2602 else if (type == ADDRESS_SYMBOLIC_TXT_REL) 2603 { 2604 if (info.offset != NULL && CONST_INT_P (info.offset) 2605 && INTVAL (info.offset) > 0) 2606 { 2607 fprintf (file, "+"); 2608 output_addr_const (file, info.offset); 2609 } 2610 fputs ("@TXTREL", file); 2611 } 2612 else if (type == ADDRESS_TLS) 2613 { 2614 switch (info.tls_type) 2615 { 2616 case TLS_GD: 2617 fputs ("@TLSGD", file); 2618 break; 2619 case TLS_LDM: 2620 fputs ("@TLSLDM", file); 2621 break; 2622 case TLS_DTPREL: 2623 fputs ("@TLSDTPREL", file); 2624 break; 2625 default : 2626 abort(); 2627 break; 2628 } 2629 } 2630 break; 2631 case ADDRESS_INVALID: 2632 fatal_insn ("invalid address", addr); 2633 break; 2634 } 2635 } 2636 2637 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol 2638 is used, so that we don't emit an .extern for it in 2639 microblaze_asm_file_end. */ 2640 2641 void 2642 microblaze_declare_object (FILE * stream, const char *name, 2643 const char *section, const char *fmt, int size) 2644 { 2645 2646 fputs (section, stream); 2647 assemble_name (stream, name); 2648 fprintf (stream, fmt, size); 2649 } 2650 2651 /* Common code to emit the insns (or to write the instructions to a file) 2652 to save/restore registers. 2653 2654 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg) 2655 is not modified within save_restore_insns. */ 2656 2657 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0) 2658 2659 /* Save or restore instructions based on whether this is the prologue or 2660 epilogue. prologue is 1 for the prologue. */ 2661 static void 2662 save_restore_insns (int prologue) 2663 { 2664 rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx = 2665 0, isr_mem_rtx = 0; 2666 rtx isr_msr_rtx = 0, insn; 2667 long mask = current_frame_info.mask; 2668 HOST_WIDE_INT gp_offset; 2669 int regno; 2670 2671 if (frame_pointer_needed 2672 && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST)) 2673 gcc_unreachable (); 2674 2675 if (mask == 0) 2676 return; 2677 2678 /* Save registers starting from high to low. The debuggers prefer at least 2679 the return register be stored at func+4, and also it allows us not to 2680 need a nop in the epilog if at least one register is reloaded in 2681 addition to return address. */ 2682 2683 /* Pick which pointer to use as a base register. For small frames, just 2684 use the stack pointer. Otherwise, use a temporary register. Save 2 2685 cycles if the save area is near the end of a large frame, by reusing 2686 the constant created in the prologue/epilogue to adjust the stack 2687 frame. */ 2688 2689 gp_offset = current_frame_info.gp_offset; 2690 2691 gcc_assert (gp_offset > 0); 2692 2693 base_reg_rtx = stack_pointer_rtx; 2694 2695 /* For interrupt_handlers, need to save/restore the MSR. */ 2696 if (microblaze_is_interrupt_variant ()) 2697 { 2698 isr_mem_rtx = gen_rtx_MEM (SImode, 2699 gen_rtx_PLUS (Pmode, base_reg_rtx, 2700 GEN_INT (current_frame_info. 2701 gp_offset - 2702 UNITS_PER_WORD))); 2703 2704 /* Do not optimize in flow analysis. */ 2705 MEM_VOLATILE_P (isr_mem_rtx) = 1; 2706 isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG); 2707 isr_msr_rtx = gen_rtx_REG (SImode, ST_REG); 2708 } 2709 2710 if (microblaze_is_interrupt_variant () && !prologue) 2711 { 2712 emit_move_insn (isr_reg_rtx, isr_mem_rtx); 2713 emit_move_insn (isr_msr_rtx, isr_reg_rtx); 2714 /* Do not optimize in flow analysis. */ 2715 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx)); 2716 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx)); 2717 } 2718 2719 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) 2720 { 2721 if (BITSET_P (mask, regno - GP_REG_FIRST)) 2722 { 2723 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM) 2724 /* Don't handle here. Already handled as the first register. */ 2725 continue; 2726 2727 reg_rtx = gen_rtx_REG (SImode, regno); 2728 insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset)); 2729 mem_rtx = gen_rtx_MEM (SImode, insn); 2730 if (microblaze_is_interrupt_variant () || save_volatiles) 2731 /* Do not optimize in flow analysis. */ 2732 MEM_VOLATILE_P (mem_rtx) = 1; 2733 2734 if (prologue) 2735 { 2736 insn = emit_move_insn (mem_rtx, reg_rtx); 2737 RTX_FRAME_RELATED_P (insn) = 1; 2738 } 2739 else 2740 { 2741 insn = emit_move_insn (reg_rtx, mem_rtx); 2742 } 2743 2744 gp_offset += GET_MODE_SIZE (SImode); 2745 } 2746 } 2747 2748 if (microblaze_is_interrupt_variant () && prologue) 2749 { 2750 emit_move_insn (isr_reg_rtx, isr_msr_rtx); 2751 emit_move_insn (isr_mem_rtx, isr_reg_rtx); 2752 2753 /* Do not optimize in flow analysis. */ 2754 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx)); 2755 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx)); 2756 } 2757 2758 /* Done saving and restoring */ 2759 } 2760 2761 2762 /* Set up the stack and frame (if desired) for the function. */ 2763 static void 2764 microblaze_function_prologue (FILE * file) 2765 { 2766 const char *fnname; 2767 long fsiz = current_frame_info.total_size; 2768 2769 /* Get the function name the same way that toplev.c does before calling 2770 assemble_start_function. This is needed so that the name used here 2771 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */ 2772 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); 2773 if (!flag_inhibit_size_directive) 2774 { 2775 fputs ("\t.ent\t", file); 2776 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname)) 2777 fputs ("_interrupt_handler", file); 2778 else if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname)) 2779 fputs ("_break_handler", file); 2780 else if (fast_interrupt && strcmp (FAST_INTERRUPT_NAME, fnname)) 2781 fputs ("_fast_interrupt", file); 2782 else 2783 assemble_name (file, fnname); 2784 fputs ("\n", file); 2785 if (!microblaze_is_interrupt_variant ()) 2786 ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function"); 2787 } 2788 2789 assemble_name (file, fnname); 2790 fputs (":\n", file); 2791 2792 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname)) 2793 fputs ("_interrupt_handler:\n", file); 2794 if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname)) 2795 fputs ("_break_handler:\n", file); 2796 if (!flag_inhibit_size_directive) 2797 { 2798 /* .frame FRAMEREG, FRAMESIZE, RETREG. */ 2799 fprintf (file, 2800 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n", 2801 (reg_names[(frame_pointer_needed) 2802 ? HARD_FRAME_POINTER_REGNUM : 2803 STACK_POINTER_REGNUM]), fsiz, 2804 reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST], 2805 current_frame_info.var_size, current_frame_info.num_gp, 2806 (int) crtl->outgoing_args_size); 2807 fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask); 2808 } 2809 } 2810 2811 /* Output extra assembler code at the end of a prologue. */ 2812 static void 2813 microblaze_function_end_prologue (FILE * file) 2814 { 2815 if (TARGET_STACK_CHECK) 2816 { 2817 fprintf (file, "\t# Stack Check Stub -- Start.\n\t"); 2818 fprintf (file, "ori\tr18,r0,_stack_end\n\t"); 2819 fprintf (file, "cmpu\tr18,r1,r18\n\t"); 2820 fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t"); 2821 fprintf (file, "# Stack Check Stub -- End.\n"); 2822 } 2823 } 2824 2825 static void 2826 microblaze_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor) 2827 { 2828 section *s; 2829 2830 if (priority != DEFAULT_INIT_PRIORITY) 2831 { 2832 char buf[18]; 2833 sprintf (buf, "%s.%.5u", 2834 is_ctor ? ".ctors" : ".dtors", 2835 MAX_INIT_PRIORITY - priority); 2836 s = get_section (buf, SECTION_WRITE, NULL_TREE); 2837 } 2838 else if (is_ctor) 2839 s = ctors_section; 2840 else 2841 s = dtors_section; 2842 2843 switch_to_section (s); 2844 assemble_align (POINTER_SIZE); 2845 fputs ("\t.word\t", asm_out_file); 2846 output_addr_const (asm_out_file, symbol); 2847 fputs ("\n", asm_out_file); 2848 } 2849 2850 /* Add a function to the list of static constructors. */ 2851 2852 static void 2853 microblaze_elf_asm_constructor (rtx symbol, int priority) 2854 { 2855 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/true); 2856 } 2857 2858 /* Add a function to the list of static destructors. */ 2859 2860 static void 2861 microblaze_elf_asm_destructor (rtx symbol, int priority) 2862 { 2863 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/false); 2864 } 2865 2866 /* Expand the prologue into a bunch of separate insns. */ 2867 2868 void 2869 microblaze_expand_prologue (void) 2870 { 2871 int regno; 2872 HOST_WIDE_INT fsiz; 2873 const char *arg_name = 0; 2874 tree fndecl = current_function_decl; 2875 tree fntype = TREE_TYPE (fndecl); 2876 tree fnargs = DECL_ARGUMENTS (fndecl); 2877 rtx next_arg_reg; 2878 int i; 2879 tree next_arg; 2880 tree cur_arg; 2881 CUMULATIVE_ARGS args_so_far_v; 2882 cumulative_args_t args_so_far; 2883 rtx mem_rtx, reg_rtx; 2884 2885 /* If struct value address is treated as the first argument, make it so. */ 2886 if (aggregate_value_p (DECL_RESULT (fndecl), fntype) 2887 && !cfun->returns_pcc_struct) 2888 { 2889 tree type = build_pointer_type (fntype); 2890 tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL, 2891 NULL_TREE, type); 2892 2893 DECL_ARG_TYPE (function_result_decl) = type; 2894 TREE_CHAIN (function_result_decl) = fnargs; 2895 fnargs = function_result_decl; 2896 } 2897 2898 /* Determine the last argument, and get its name. */ 2899 2900 INIT_CUMULATIVE_ARGS (args_so_far_v, fntype, NULL_RTX, 0, 0); 2901 args_so_far = pack_cumulative_args (&args_so_far_v); 2902 regno = GP_ARG_FIRST; 2903 2904 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg) 2905 { 2906 tree passed_type = DECL_ARG_TYPE (cur_arg); 2907 machine_mode passed_mode = TYPE_MODE (passed_type); 2908 rtx entry_parm; 2909 2910 if (TREE_ADDRESSABLE (passed_type)) 2911 { 2912 passed_type = build_pointer_type (passed_type); 2913 passed_mode = Pmode; 2914 } 2915 2916 function_arg_info arg (passed_type, passed_mode, /*named=*/true); 2917 entry_parm = targetm.calls.function_arg (args_so_far, arg); 2918 2919 if (entry_parm) 2920 { 2921 int words; 2922 2923 /* passed in a register, so will get homed automatically. */ 2924 if (GET_MODE (entry_parm) == BLKmode) 2925 words = (int_size_in_bytes (passed_type) + 3) / 4; 2926 else 2927 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4; 2928 2929 regno = REGNO (entry_parm) + words - 1; 2930 } 2931 else 2932 { 2933 regno = GP_ARG_LAST + 1; 2934 break; 2935 } 2936 2937 targetm.calls.function_arg_advance (args_so_far, arg); 2938 2939 next_arg = TREE_CHAIN (cur_arg); 2940 if (next_arg == 0) 2941 { 2942 if (DECL_NAME (cur_arg)) 2943 arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg)); 2944 2945 break; 2946 } 2947 } 2948 2949 /* Split parallel insn into a sequence of insns. */ 2950 2951 next_arg_reg = targetm.calls.function_arg (args_so_far, 2952 function_arg_info::end_marker ()); 2953 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL) 2954 { 2955 rtvec adjust = XVEC (next_arg_reg, 0); 2956 int num = GET_NUM_ELEM (adjust); 2957 2958 for (i = 0; i < num; i++) 2959 { 2960 rtx pattern = RTVEC_ELT (adjust, i); 2961 emit_insn (pattern); 2962 } 2963 } 2964 2965 fsiz = compute_frame_size (get_frame_size ()); 2966 2967 if (flag_stack_usage_info) 2968 current_function_static_stack_size = fsiz; 2969 2970 /* If this function is a varargs function, store any registers that 2971 would normally hold arguments ($5 - $10) on the stack. */ 2972 if (((TYPE_ARG_TYPES (fntype) != 0 2973 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) 2974 != void_type_node)) 2975 || (arg_name != 0 2976 && ((arg_name[0] == '_' 2977 && strcmp (arg_name, "__builtin_va_alist") == 0) 2978 || (arg_name[0] == 'v' 2979 && strcmp (arg_name, "va_alist") == 0))))) 2980 { 2981 int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD; 2982 rtx ptr = stack_pointer_rtx; 2983 2984 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */ 2985 for (; regno <= GP_ARG_LAST; regno++) 2986 { 2987 if (offset != 0) 2988 ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset)); 2989 emit_move_insn (gen_rtx_MEM (SImode, ptr), 2990 gen_rtx_REG (SImode, regno)); 2991 2992 offset += GET_MODE_SIZE (SImode); 2993 } 2994 } 2995 2996 if (fsiz > 0) 2997 { 2998 rtx fsiz_rtx = GEN_INT (fsiz); 2999 3000 rtx_insn *insn = NULL; 3001 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, 3002 fsiz_rtx)); 3003 if (insn) 3004 RTX_FRAME_RELATED_P (insn) = 1; 3005 3006 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */ 3007 if (!crtl->is_leaf || interrupt_handler) 3008 { 3009 mem_rtx = gen_rtx_MEM (SImode, 3010 gen_rtx_PLUS (Pmode, stack_pointer_rtx, 3011 const0_rtx)); 3012 3013 if (interrupt_handler) 3014 /* Do not optimize in flow analysis. */ 3015 MEM_VOLATILE_P (mem_rtx) = 1; 3016 3017 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM); 3018 insn = emit_move_insn (mem_rtx, reg_rtx); 3019 RTX_FRAME_RELATED_P (insn) = 1; 3020 } 3021 3022 /* _save_ registers for prologue. */ 3023 save_restore_insns (1); 3024 3025 if (frame_pointer_needed) 3026 { 3027 rtx_insn *insn = 0; 3028 3029 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx, 3030 stack_pointer_rtx)); 3031 3032 if (insn) 3033 RTX_FRAME_RELATED_P (insn) = 1; 3034 } 3035 } 3036 3037 if ((flag_pic == 2 || TLS_NEEDS_GOT ) 3038 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM)) 3039 { 3040 if ((flag_pic == 2 && !TARGET_PIC_DATA_TEXT_REL) || TLS_NEEDS_GOT) 3041 { 3042 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM); 3043 /* setting GOT. */ 3044 emit_insn (gen_set_got (pic_offset_table_rtx)); 3045 } 3046 else 3047 { 3048 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM); 3049 /* setting start of text. */ 3050 emit_insn (gen_set_text (pic_offset_table_rtx)); 3051 } 3052 } 3053 3054 /* If we are profiling, make sure no instructions are scheduled before 3055 the call to mcount. */ 3056 3057 if (profile_flag) 3058 emit_insn (gen_blockage ()); 3059 } 3060 3061 /* Do necessary cleanup after a function to restore stack, frame, and regs. */ 3062 3063 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */ 3064 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST)) 3065 3066 static void 3067 microblaze_function_epilogue (FILE *file) 3068 { 3069 const char *fnname; 3070 3071 /* Get the function name the same way that toplev.c does before calling 3072 assemble_start_function. This is needed so that the name used here 3073 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */ 3074 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); 3075 3076 if (!flag_inhibit_size_directive) 3077 { 3078 fputs ("\t.end\t", file); 3079 if (interrupt_handler && !break_handler) 3080 fputs ("_interrupt_handler", file); 3081 else if (break_handler) 3082 fputs ("_break_handler", file); 3083 else 3084 assemble_name (file, fnname); 3085 fputs ("\n", file); 3086 } 3087 3088 /* Reset state info for each function. */ 3089 current_frame_info = zero_frame_info; 3090 3091 /* Restore the output file if optimizing the GP (optimizing the GP causes 3092 the text to be diverted to a tempfile, so that data decls come before 3093 references to the data). */ 3094 } 3095 3096 /* Expand the epilogue into a bunch of separate insns. */ 3097 3098 void 3099 microblaze_expand_epilogue (void) 3100 { 3101 HOST_WIDE_INT fsiz = current_frame_info.total_size; 3102 rtx fsiz_rtx = GEN_INT (fsiz); 3103 rtx reg_rtx; 3104 rtx mem_rtx; 3105 3106 /* In case of interrupt handlers use addki instead of addi for changing the 3107 stack pointer value. */ 3108 3109 if (microblaze_can_use_return_insn ()) 3110 { 3111 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, 3112 GP_REG_FIRST + 3113 MB_ABI_SUB_RETURN_ADDR_REGNUM))); 3114 return; 3115 } 3116 3117 if (fsiz > 0) 3118 { 3119 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the 3120 sequence of load-followed by a use (in rtsd) in every prologue. Saves 3121 a load-use stall cycle :) This is also important to handle alloca. 3122 (See comments for if (frame_pointer_needed) below. */ 3123 3124 if (!crtl->is_leaf || interrupt_handler) 3125 { 3126 mem_rtx = 3127 gen_rtx_MEM (SImode, 3128 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx)); 3129 if (interrupt_handler) 3130 /* Do not optimize in flow analysis. */ 3131 MEM_VOLATILE_P (mem_rtx) = 1; 3132 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM); 3133 emit_move_insn (reg_rtx, mem_rtx); 3134 } 3135 3136 /* It is important that this is done after we restore the return address 3137 register (above). When alloca is used, we want to restore the 3138 sub-routine return address only from the current stack top and not 3139 from the frame pointer (which we restore below). (frame_pointer + 0) 3140 might have been over-written since alloca allocates memory on the 3141 current stack. */ 3142 if (frame_pointer_needed) 3143 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx)); 3144 3145 /* _restore_ registers for epilogue. */ 3146 save_restore_insns (0); 3147 emit_insn (gen_blockage ()); 3148 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx)); 3149 } 3150 3151 if (crtl->calls_eh_return) 3152 emit_insn (gen_addsi3 (stack_pointer_rtx, 3153 stack_pointer_rtx, 3154 gen_raw_REG (SImode, 3155 MB_EH_STACKADJ_REGNUM))); 3156 3157 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST + 3158 MB_ABI_SUB_RETURN_ADDR_REGNUM))); 3159 } 3160 3161 3162 /* Return nonzero if this function is known to have a null epilogue. 3163 This allows the optimizer to omit jumps to jumps if no stack 3164 was created. */ 3165 3166 int 3167 microblaze_can_use_return_insn (void) 3168 { 3169 if (!reload_completed) 3170 return 0; 3171 3172 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag) 3173 return 0; 3174 3175 if (current_frame_info.initialized) 3176 return current_frame_info.total_size == 0; 3177 3178 return compute_frame_size (get_frame_size ()) == 0; 3179 } 3180 3181 /* Implement TARGET_SECONDARY_RELOAD. */ 3182 3183 static reg_class_t 3184 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED, 3185 reg_class_t rclass, machine_mode mode ATTRIBUTE_UNUSED, 3186 secondary_reload_info *sri ATTRIBUTE_UNUSED) 3187 { 3188 if (rclass == ST_REGS) 3189 return GR_REGS; 3190 3191 return NO_REGS; 3192 } 3193 3194 static void 3195 microblaze_globalize_label (FILE * stream, const char *name) 3196 { 3197 fputs ("\t.globl\t", stream); 3198 if (microblaze_is_interrupt_variant ()) 3199 { 3200 if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME)) 3201 fputs (INTERRUPT_HANDLER_NAME, stream); 3202 else if (break_handler && strcmp (name, BREAK_HANDLER_NAME)) 3203 fputs (BREAK_HANDLER_NAME, stream); 3204 else if (fast_interrupt && strcmp (name, FAST_INTERRUPT_NAME)) 3205 fputs (FAST_INTERRUPT_NAME, stream); 3206 fputs ("\n\t.globl\t", stream); 3207 } 3208 assemble_name (stream, name); 3209 fputs ("\n", stream); 3210 } 3211 3212 /* Returns true if decl should be placed into a "small data" section. */ 3213 static bool 3214 microblaze_elf_in_small_data_p (const_tree decl) 3215 { 3216 HOST_WIDE_INT size; 3217 3218 if (!TARGET_XLGPOPT) 3219 return false; 3220 3221 /* We want to merge strings, so we never consider them small data. */ 3222 if (TREE_CODE (decl) == STRING_CST) 3223 return false; 3224 3225 /* Functions are never in the small data area. */ 3226 if (TREE_CODE (decl) == FUNCTION_DECL) 3227 return false; 3228 3229 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl)) 3230 { 3231 const char *section = DECL_SECTION_NAME (decl); 3232 if (strcmp (section, ".sdata") == 0 3233 || strcmp (section, ".sdata2") == 0 3234 || strcmp (section, ".sbss") == 0 3235 || strcmp (section, ".sbss2") == 0) 3236 return true; 3237 } 3238 3239 size = int_size_in_bytes (TREE_TYPE (decl)); 3240 3241 return (size > 0 && size <= microblaze_section_threshold); 3242 } 3243 3244 /* We need to disable address diff vectors in 3245 case of pic data text relative mode. */ 3246 3247 static bool 3248 microblaze_gen_pic_addr_dif_vec (void) 3249 { 3250 return (flag_pic && !TARGET_PIC_DATA_TEXT_REL); 3251 } 3252 3253 static section * 3254 microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) 3255 { 3256 switch (categorize_decl_for_section (decl, reloc)) 3257 { 3258 case SECCAT_RODATA_MERGE_STR: 3259 case SECCAT_RODATA_MERGE_STR_INIT: 3260 /* MB binutils have various issues with mergeable string sections and 3261 relaxation/relocation. Currently, turning mergeable sections 3262 into regular readonly sections. */ 3263 3264 return readonly_data_section; 3265 default: 3266 return default_elf_select_section (decl, reloc, align); 3267 } 3268 } 3269 3270 /* 3271 Encode info about sections into the RTL based on a symbol's declaration. 3272 The default definition of this hook, default_encode_section_info in 3273 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */ 3274 3275 static void 3276 microblaze_encode_section_info (tree decl, rtx rtl, int first) 3277 { 3278 default_encode_section_info (decl, rtl, first); 3279 } 3280 3281 static rtx 3282 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED, rtx op) 3283 { 3284 rtx result; 3285 bool isFunc = (GET_CODE (op) == SYMBOL_REF 3286 && (SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_FUNCTION)); 3287 result = (!TARGET_PIC_DATA_TEXT_REL) 3288 ? gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF) 3289 : gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_TEXT); 3290 result = gen_rtx_CONST (Pmode, result); 3291 result = (TARGET_PIC_DATA_TEXT_REL && isFunc) 3292 ? gen_rtx_PLUS (Pmode, gen_raw_REG (Pmode, 3293 get_base_reg (op)), result) 3294 : gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result); 3295 result = (!TARGET_PIC_DATA_TEXT_REL) 3296 ? gen_const_mem (Pmode, result) : result; 3297 3298 return result; 3299 } 3300 3301 static void 3302 microblaze_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, 3303 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, 3304 tree function) 3305 { 3306 const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl)); 3307 rtx this_rtx, funexp; 3308 rtx_insn *insn; 3309 3310 reload_completed = 1; 3311 epilogue_completed = 1; 3312 3313 /* Mark the end of the (empty) prologue. */ 3314 emit_note (NOTE_INSN_PROLOGUE_END); 3315 3316 /* Find the "this" pointer. If the function returns a structure, 3317 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */ 3318 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) 3319 this_rtx = gen_rtx_REG (Pmode, (MB_ABI_FIRST_ARG_REGNUM + 1)); 3320 else 3321 this_rtx = gen_rtx_REG (Pmode, MB_ABI_FIRST_ARG_REGNUM); 3322 3323 /* Apply the constant offset, if required. */ 3324 if (delta) 3325 emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta))); 3326 3327 /* Apply the offset from the vtable, if required. */ 3328 if (vcall_offset) 3329 { 3330 rtx vcall_offset_rtx = GEN_INT (vcall_offset); 3331 rtx temp1 = gen_rtx_REG (Pmode, MB_ABI_TEMP1_REGNUM); 3332 3333 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx)); 3334 3335 rtx loc = gen_rtx_PLUS (Pmode, temp1, vcall_offset_rtx); 3336 emit_move_insn (temp1, gen_rtx_MEM (Pmode, loc)); 3337 3338 emit_insn (gen_addsi3 (this_rtx, this_rtx, temp1)); 3339 } 3340 3341 /* Generate a tail call to the target function. */ 3342 if (!TREE_USED (function)) 3343 { 3344 assemble_external (function); 3345 TREE_USED (function) = 1; 3346 } 3347 3348 funexp = XEXP (DECL_RTL (function), 0); 3349 rtx temp2 = gen_rtx_REG (Pmode, MB_ABI_TEMP2_REGNUM); 3350 3351 if (flag_pic) 3352 emit_move_insn (temp2, expand_pic_symbol_ref (Pmode, funexp)); 3353 else 3354 emit_move_insn (temp2, funexp); 3355 3356 emit_insn (gen_indirect_jump (temp2)); 3357 3358 /* Run just enough of rest_of_compilation. This sequence was 3359 "borrowed" from rs6000.c. */ 3360 insn = get_insns (); 3361 shorten_branches (insn); 3362 assemble_start_function (thunk_fndecl, fnname); 3363 final_start_function (insn, file, 1); 3364 final (insn, file, 1); 3365 final_end_function (); 3366 assemble_end_function (thunk_fndecl, fnname); 3367 3368 reload_completed = 0; 3369 epilogue_completed = 0; 3370 } 3371 3372 bool 3373 microblaze_expand_move (machine_mode mode, rtx operands[]) 3374 { 3375 rtx op0, op1; 3376 3377 op0 = operands[0]; 3378 op1 = operands[1]; 3379 3380 if (!register_operand (op0, SImode) 3381 && !register_operand (op1, SImode) 3382 && (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0)) 3383 { 3384 rtx temp = force_reg (SImode, op1); 3385 emit_move_insn (op0, temp); 3386 return true; 3387 } 3388 /* If operands[1] is a constant address invalid for pic, then we need to 3389 handle it just like LEGITIMIZE_ADDRESS does. */ 3390 if (GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF) 3391 { 3392 rtx result; 3393 if (microblaze_tls_symbol_p(op1)) 3394 { 3395 result = microblaze_legitimize_tls_address (op1, NULL_RTX); 3396 emit_move_insn (op0, result); 3397 return true; 3398 } 3399 else if (flag_pic) 3400 { 3401 if (reload_in_progress) 3402 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); 3403 result = expand_pic_symbol_ref (mode, op1); 3404 3405 if (TARGET_PIC_DATA_TEXT_REL && GET_CODE (op0) == REG 3406 && REGNO (op0) >= FIRST_PSEUDO_REGISTER) 3407 result = force_reg (SImode, result); 3408 3409 emit_move_insn (op0, result); 3410 return true; 3411 } 3412 } 3413 if (GET_CODE (op1) == PLUS && GET_CODE (XEXP (op1,1)) == CONST) 3414 { 3415 rtx p0, p1, result, temp; 3416 3417 p0 = XEXP (XEXP (op1,1), 0); 3418 3419 if (GET_CODE (p0) == PLUS) 3420 { 3421 p1 = XEXP (p0, 1); 3422 p0 = XEXP (p0, 0); 3423 } 3424 3425 if (GET_CODE (p0) == UNSPEC && GET_CODE (p1) == CONST_INT 3426 && flag_pic && TARGET_PIC_DATA_TEXT_REL) 3427 { 3428 result = gen_rtx_CONST (Pmode, p0); 3429 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result); 3430 temp = force_reg (SImode, result); 3431 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, p1)); 3432 return true; 3433 } 3434 } 3435 /* Handle Case of (const (plus symbol const_int)). */ 3436 if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1,0)) == PLUS) 3437 { 3438 rtx p0, p1; 3439 3440 p0 = XEXP (XEXP (op1, 0), 0); 3441 p1 = XEXP (XEXP (op1, 0), 1); 3442 3443 if ((GET_CODE (p1) == CONST_INT) 3444 && ((GET_CODE (p0) == UNSPEC) 3445 || ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF) 3446 && (flag_pic == 2 || microblaze_tls_symbol_p (p0) 3447 || !SMALL_INT (p1))))) 3448 { 3449 rtx temp = force_reg (SImode, p0); 3450 rtx temp2 = p1; 3451 3452 if (flag_pic && reload_in_progress) 3453 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); 3454 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, temp2)); 3455 return true; 3456 } 3457 } 3458 return false; 3459 } 3460 3461 /* Expand shift operations. */ 3462 int 3463 microblaze_expand_shift (rtx operands[]) 3464 { 3465 gcc_assert ((GET_CODE (operands[2]) == CONST_INT) 3466 || (GET_CODE (operands[2]) == REG) 3467 || (GET_CODE (operands[2]) == SUBREG)); 3468 3469 /* Shift by one -- generate pattern. */ 3470 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1)) 3471 return 0; 3472 3473 /* Have barrel shifter and shift > 1: use it. */ 3474 if (TARGET_BARREL_SHIFT) 3475 return 0; 3476 3477 gcc_assert ((GET_CODE (operands[0]) == REG) 3478 || (GET_CODE (operands[0]) == SUBREG) 3479 || (GET_CODE (operands[1]) == REG) 3480 || (GET_CODE (operands[1]) == SUBREG)); 3481 3482 /* Shift by zero -- copy regs if necessary. */ 3483 if (operands[2] == const0_rtx 3484 && !rtx_equal_p (operands[0], operands[1])) 3485 { 3486 emit_insn (gen_movsi (operands[0], operands[1])); 3487 return 1; 3488 } 3489 3490 return 0; 3491 } 3492 3493 /* Return an RTX indicating where the return address to the 3494 calling function can be found. */ 3495 rtx 3496 microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) 3497 { 3498 if (count != 0) 3499 return NULL_RTX; 3500 3501 return get_hard_reg_initial_val (Pmode, 3502 MB_ABI_SUB_RETURN_ADDR_REGNUM); 3503 } 3504 3505 void 3506 microblaze_eh_return (rtx op0) 3507 { 3508 emit_insn (gen_movsi (gen_rtx_MEM (Pmode, stack_pointer_rtx), op0)); 3509 } 3510 3511 /* Queue an .ident string in the queue of top-level asm statements. 3512 If the string size is below the threshold, put it into .sdata2. 3513 If the front-end is done, we must be being called from toplev.c. 3514 In that case, do nothing. */ 3515 void 3516 microblaze_asm_output_ident (const char *string) 3517 { 3518 const char *section_asm_op; 3519 int size; 3520 char *buf; 3521 3522 if (symtab->state != PARSING) 3523 return; 3524 3525 size = strlen (string) + 1; 3526 if (size <= microblaze_section_threshold) 3527 section_asm_op = SDATA2_SECTION_ASM_OP; 3528 else 3529 section_asm_op = READONLY_DATA_SECTION_ASM_OP; 3530 3531 buf = ACONCAT (("\t.pushsection", section_asm_op, 3532 "\n\t.ascii \"", string, "\\0\"\n", 3533 "\t.popsection\n", NULL)); 3534 symtab->finalize_toplevel_asm (build_string (strlen (buf), buf)); 3535 } 3536 3537 static void 3538 microblaze_elf_asm_init_sections (void) 3539 { 3540 sdata2_section 3541 = get_unnamed_section (SECTION_WRITE, output_section_asm_op, 3542 SDATA2_SECTION_ASM_OP); 3543 } 3544 3545 /* Generate assembler code for constant parts of a trampoline. */ 3546 3547 static void 3548 microblaze_asm_trampoline_template (FILE *f) 3549 { 3550 fprintf (f, "\tmfs r18, rpc\n"); 3551 fprintf (f, "\tlwi r3, r18, 16\n"); 3552 fprintf (f, "\tlwi r18, r18, 20\n"); 3553 fprintf (f, "\tbra r18\n"); 3554 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */ 3555 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */ 3556 } 3557 3558 /* Implement TARGET_TRAMPOLINE_INIT. */ 3559 3560 static void 3561 microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) 3562 { 3563 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); 3564 rtx mem; 3565 3566 emit_block_move (m_tramp, assemble_trampoline_template (), 3567 GEN_INT (6*UNITS_PER_WORD), BLOCK_OP_NORMAL); 3568 3569 mem = adjust_address (m_tramp, SImode, 16); 3570 emit_move_insn (mem, chain_value); 3571 mem = adjust_address (m_tramp, SImode, 20); 3572 emit_move_insn (mem, fnaddr); 3573 } 3574 3575 /* Generate conditional branch -- first, generate test condition, 3576 second, generate correct branch instruction. */ 3577 3578 void 3579 microblaze_expand_conditional_branch (machine_mode mode, rtx operands[]) 3580 { 3581 enum rtx_code code = GET_CODE (operands[0]); 3582 rtx cmp_op0 = operands[1]; 3583 rtx cmp_op1 = operands[2]; 3584 rtx label1 = operands[3]; 3585 rtx comp_reg = gen_reg_rtx (SImode); 3586 rtx condition; 3587 3588 gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG)); 3589 3590 /* If comparing against zero, just test source reg. */ 3591 if (cmp_op1 == const0_rtx) 3592 { 3593 comp_reg = cmp_op0; 3594 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx); 3595 emit_jump_insn (gen_condjump (condition, label1)); 3596 } 3597 3598 else if (code == EQ || code == NE) 3599 { 3600 /* Use xor for equal/not-equal comparison. */ 3601 emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1)); 3602 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx); 3603 emit_jump_insn (gen_condjump (condition, label1)); 3604 } 3605 else 3606 { 3607 /* Generate compare and branch in single instruction. */ 3608 cmp_op1 = force_reg (mode, cmp_op1); 3609 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1); 3610 emit_jump_insn (gen_branch_compare(condition, cmp_op0, cmp_op1, label1)); 3611 } 3612 } 3613 3614 void 3615 microblaze_expand_conditional_branch_reg (machine_mode mode, rtx operands[]) 3616 { 3617 enum rtx_code code = GET_CODE (operands[0]); 3618 rtx cmp_op0 = operands[1]; 3619 rtx cmp_op1 = operands[2]; 3620 rtx label1 = operands[3]; 3621 rtx comp_reg = gen_reg_rtx (SImode); 3622 rtx condition; 3623 3624 gcc_assert ((GET_CODE (cmp_op0) == REG) 3625 || (GET_CODE (cmp_op0) == SUBREG)); 3626 3627 /* If comparing against zero, just test source reg. */ 3628 if (cmp_op1 == const0_rtx) 3629 { 3630 comp_reg = cmp_op0; 3631 condition = gen_rtx_fmt_ee (signed_condition (code), 3632 SImode, comp_reg, const0_rtx); 3633 emit_jump_insn (gen_condjump (condition, label1)); 3634 } 3635 else if (code == EQ) 3636 { 3637 emit_insn (gen_seq_internal_pat (comp_reg, 3638 cmp_op0, cmp_op1)); 3639 condition = gen_rtx_EQ (SImode, comp_reg, const0_rtx); 3640 emit_jump_insn (gen_condjump (condition, label1)); 3641 } 3642 else if (code == NE) 3643 { 3644 emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0, 3645 cmp_op1)); 3646 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx); 3647 emit_jump_insn (gen_condjump (condition, label1)); 3648 } 3649 else 3650 { 3651 /* Generate compare and branch in single instruction. */ 3652 cmp_op1 = force_reg (mode, cmp_op1); 3653 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1); 3654 emit_jump_insn (gen_branch_compare (condition, cmp_op0, 3655 cmp_op1, label1)); 3656 } 3657 } 3658 3659 void 3660 microblaze_expand_conditional_branch_sf (rtx operands[]) 3661 { 3662 rtx condition; 3663 rtx cmp_op0 = XEXP (operands[0], 0); 3664 rtx cmp_op1 = XEXP (operands[0], 1); 3665 rtx comp_reg = gen_reg_rtx (SImode); 3666 3667 emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1)); 3668 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx); 3669 emit_jump_insn (gen_condjump (condition, operands[3])); 3670 } 3671 3672 /* Implement TARGET_FRAME_POINTER_REQUIRED. */ 3673 3674 static bool 3675 microblaze_frame_pointer_required (void) 3676 { 3677 /* If the function contains dynamic stack allocations, we need to 3678 use the frame pointer to access the static parts of the frame. */ 3679 if (cfun->calls_alloca) 3680 return true; 3681 return false; 3682 } 3683 3684 void 3685 microblaze_expand_divide (rtx operands[]) 3686 { 3687 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */ 3688 3689 rtx regt1 = gen_reg_rtx (SImode); 3690 rtx reg18 = gen_rtx_REG (SImode, R_TMP); 3691 rtx regqi = gen_reg_rtx (QImode); 3692 rtx_code_label *div_label = gen_label_rtx (); 3693 rtx_code_label *div_end_label = gen_label_rtx (); 3694 rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table"); 3695 rtx mem_rtx; 3696 rtx ret; 3697 rtx_insn *jump, *cjump, *insn; 3698 3699 insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2])); 3700 cjump = emit_jump_insn_after (gen_cbranchsi4 ( 3701 gen_rtx_GTU (SImode, regt1, GEN_INT (15)), 3702 regt1, GEN_INT (15), div_label), insn); 3703 LABEL_NUSES (div_label) = 1; 3704 JUMP_LABEL (cjump) = div_label; 3705 emit_insn (gen_rtx_CLOBBER (SImode, reg18)); 3706 3707 emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4))); 3708 emit_insn (gen_addsi3 (regt1, regt1, operands[2])); 3709 mem_rtx = gen_rtx_MEM (QImode, 3710 gen_rtx_PLUS (Pmode, regt1, div_table_rtx)); 3711 3712 insn = emit_insn (gen_movqi (regqi, mem_rtx)); 3713 insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0))); 3714 jump = emit_jump_insn_after (gen_jump (div_end_label), insn); 3715 JUMP_LABEL (jump) = div_end_label; 3716 LABEL_NUSES (div_end_label) = 1; 3717 emit_barrier (); 3718 3719 emit_label (div_label); 3720 ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"), 3721 operands[0], LCT_NORMAL, 3722 GET_MODE (operands[0]), 3723 operands[1], GET_MODE (operands[1]), 3724 operands[2], GET_MODE (operands[2])); 3725 if (ret != operands[0]) 3726 emit_move_insn (operands[0], ret); 3727 3728 emit_label (div_end_label); 3729 emit_insn (gen_blockage ()); 3730 } 3731 3732 /* Implement TARGET_FUNCTION_VALUE. */ 3733 static rtx 3734 microblaze_function_value (const_tree valtype, 3735 const_tree func ATTRIBUTE_UNUSED, 3736 bool outgoing ATTRIBUTE_UNUSED) 3737 { 3738 return LIBCALL_VALUE (TYPE_MODE (valtype)); 3739 } 3740 3741 /* Implement TARGET_SCHED_ADJUST_COST. */ 3742 static int 3743 microblaze_adjust_cost (rtx_insn *, int dep_type, rtx_insn *, int cost, 3744 unsigned int) 3745 { 3746 if (dep_type == REG_DEP_OUTPUT || dep_type == 0) 3747 return cost; 3748 return 0; 3749 } 3750 3751 /* Implement TARGET_LEGITIMATE_CONSTANT_P. 3752 3753 At present, GAS doesn't understand li.[sd], so don't allow it 3754 to be generated at present. */ 3755 static bool 3756 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x) 3757 { 3758 3759 if (microblaze_cannot_force_const_mem(mode, x)) 3760 return false; 3761 3762 if (GET_CODE (x) == CONST_DOUBLE) 3763 { 3764 return microblaze_const_double_ok (x, GET_MODE (x)); 3765 } 3766 3767 /* Handle Case of (const (plus unspec const_int)). */ 3768 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS) 3769 { 3770 rtx p0, p1; 3771 3772 p0 = XEXP (XEXP (x, 0), 0); 3773 p1 = XEXP (XEXP (x, 0), 1); 3774 3775 if (GET_CODE(p1) == CONST_INT) 3776 { 3777 /* Const offset from UNSPEC is not supported. */ 3778 if ((GET_CODE (p0) == UNSPEC)) 3779 return false; 3780 3781 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF) 3782 && (microblaze_tls_symbol_p (p0) || !SMALL_INT (p1))) 3783 return false; 3784 } 3785 } 3786 3787 return true; 3788 } 3789 3790 static rtx 3791 get_branch_target (rtx branch) 3792 { 3793 if (CALL_P (branch)) 3794 { 3795 rtx call; 3796 3797 call = XVECEXP (PATTERN (branch), 0, 0); 3798 if (GET_CODE (call) == SET) 3799 call = SET_SRC (call); 3800 if (GET_CODE (call) != CALL) 3801 abort (); 3802 return XEXP (XEXP (call, 0), 0); 3803 } 3804 3805 return NULL_RTX; 3806 } 3807 3808 /* Heuristics to identify where to insert at the 3809 fall through path of the caller function. If there 3810 is a call after the caller branch delay slot then 3811 we dont generate the instruction prefetch instruction. 3812 3813 Scan up to 32 instructions after the call and checks 3814 for the JUMP and call instruction . If there is a call 3815 or JUMP instruction in the range of 32 instruction "wic" 3816 instruction wont be generated. Otherwise insert the "wic" 3817 instruction in the fall through of the call instruction 3818 four instruction after the call. before_4 is used for 3819 the position to insert "wic" instructions. before_16 is 3820 used to check for call and JUMP instruction for first 3821 15 insns. */ 3822 3823 static void 3824 insert_wic_for_ilb_runout (rtx_insn *first) 3825 { 3826 rtx_insn *insn; 3827 rtx_insn *before_4 = 0; 3828 rtx_insn *before_16 = 0; 3829 int addr_offset = 0; 3830 int length; 3831 int wic_addr0 = 128 * 4; 3832 3833 int first_addr = INSN_ADDRESSES (INSN_UID (first)); 3834 3835 for (insn = first; insn; insn = NEXT_INSN (insn)) 3836 if (INSN_P (insn)) 3837 { 3838 addr_offset = INSN_ADDRESSES (INSN_UID (insn)) - first_addr; 3839 length = get_attr_length (insn); 3840 if (before_4 == 0 && addr_offset + length >= 4 * 4) 3841 before_4 = insn; 3842 3843 if (JUMP_P(insn)) 3844 return; 3845 if (before_16 == 0 && addr_offset + length >= 14 * 4) 3846 before_16 = insn; 3847 if (CALL_P (insn) || tablejump_p (insn, 0, 0)) 3848 return; 3849 if (addr_offset + length >= 32 * 4) 3850 { 3851 gcc_assert (before_4 && before_16); 3852 if (wic_addr0 > 4 * 4) 3853 { 3854 insn = 3855 emit_insn_before (gen_iprefetch 3856 (gen_int_mode (addr_offset, SImode)), 3857 before_4); 3858 recog_memoized (insn); 3859 INSN_LOCATION (insn) = INSN_LOCATION (before_4); 3860 INSN_ADDRESSES_NEW (insn, INSN_ADDRESSES (INSN_UID (before_4))); 3861 return; 3862 } 3863 } 3864 } 3865 } 3866 3867 /* Insert instruction prefetch instruction at the fall 3868 through path of the function call. */ 3869 3870 static void 3871 insert_wic (void) 3872 { 3873 rtx_insn *insn; 3874 int i; 3875 basic_block bb, prev = 0; 3876 rtx branch_target = 0; 3877 3878 shorten_branches (get_insns ()); 3879 3880 for (i = 0; i < n_basic_blocks_for_fn (cfun) - 1; i++) 3881 { 3882 edge e; 3883 edge_iterator ei; 3884 bool simple_loop = false; 3885 3886 bb = BASIC_BLOCK_FOR_FN (cfun, i); 3887 3888 if (bb == NULL) 3889 continue; 3890 3891 if ((prev != 0) && (prev != bb)) 3892 continue; 3893 else 3894 prev = 0; 3895 3896 FOR_EACH_EDGE (e, ei, bb->preds) 3897 if (e->src == bb) 3898 { 3899 simple_loop = true; 3900 prev= e->dest; 3901 break; 3902 } 3903 3904 for (insn = BB_END (bb); insn; insn = PREV_INSN (insn)) 3905 { 3906 if (INSN_P (insn) && !simple_loop 3907 && CALL_P(insn)) 3908 { 3909 if ((branch_target = get_branch_target (insn))) 3910 insert_wic_for_ilb_runout ( 3911 next_active_insn (next_active_insn (insn))); 3912 } 3913 if (insn == BB_HEAD (bb)) 3914 break; 3915 } 3916 } 3917 } 3918 3919 /* The reorg function defined through the macro 3920 TARGET_MACHINE_DEPENDENT_REORG. */ 3921 3922 static void 3923 microblaze_machine_dependent_reorg (void) 3924 { 3925 if (TARGET_PREFETCH) 3926 { 3927 compute_bb_for_insn (); 3928 loop_optimizer_init (AVOID_CFG_MODIFICATIONS); 3929 shorten_branches (get_insns ()); 3930 insert_wic (); 3931 loop_optimizer_finalize (); 3932 free_bb_for_insn (); 3933 return; 3934 } 3935 } 3936 3937 /* Implement TARGET_CONSTANT_ALIGNMENT. */ 3938 3939 static HOST_WIDE_INT 3940 microblaze_constant_alignment (const_tree exp, HOST_WIDE_INT align) 3941 { 3942 if (TREE_CODE (exp) == STRING_CST || TREE_CODE (exp) == CONSTRUCTOR) 3943 return MAX (align, BITS_PER_WORD); 3944 return align; 3945 } 3946 3947 /* Implement TARGET_STARTING_FRAME_OFFSET. */ 3948 3949 static HOST_WIDE_INT 3950 microblaze_starting_frame_offset (void) 3951 { 3952 return (crtl->outgoing_args_size + FIRST_PARM_OFFSET(FNDECL)); 3953 } 3954 3955 #undef TARGET_ENCODE_SECTION_INFO 3956 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info 3957 3958 #undef TARGET_ASM_GLOBALIZE_LABEL 3959 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label 3960 3961 #undef TARGET_ASM_FUNCTION_PROLOGUE 3962 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue 3963 3964 #undef TARGET_ASM_FUNCTION_EPILOGUE 3965 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue 3966 3967 #undef TARGET_RTX_COSTS 3968 #define TARGET_RTX_COSTS microblaze_rtx_costs 3969 3970 #undef TARGET_CANNOT_FORCE_CONST_MEM 3971 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem 3972 3973 #undef TARGET_ADDRESS_COST 3974 #define TARGET_ADDRESS_COST microblaze_address_cost 3975 3976 #undef TARGET_ATTRIBUTE_TABLE 3977 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table 3978 3979 #undef TARGET_IN_SMALL_DATA_P 3980 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p 3981 3982 #undef TARGET_ASM_SELECT_SECTION 3983 #define TARGET_ASM_SELECT_SECTION microblaze_select_section 3984 3985 #undef TARGET_HAVE_SRODATA_SECTION 3986 #define TARGET_HAVE_SRODATA_SECTION true 3987 3988 #undef TARGET_ASM_FUNCTION_END_PROLOGUE 3989 #define TARGET_ASM_FUNCTION_END_PROLOGUE \ 3990 microblaze_function_end_prologue 3991 3992 #undef TARGET_ARG_PARTIAL_BYTES 3993 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes 3994 3995 #undef TARGET_FUNCTION_ARG 3996 #define TARGET_FUNCTION_ARG microblaze_function_arg 3997 3998 #undef TARGET_FUNCTION_ARG_ADVANCE 3999 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance 4000 4001 #undef TARGET_CAN_ELIMINATE 4002 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate 4003 4004 #undef TARGET_LEGITIMIZE_ADDRESS 4005 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address 4006 4007 #undef TARGET_LEGITIMATE_ADDRESS_P 4008 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p 4009 4010 #undef TARGET_LRA_P 4011 #define TARGET_LRA_P hook_bool_void_false 4012 4013 #undef TARGET_FRAME_POINTER_REQUIRED 4014 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required 4015 4016 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE 4017 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template 4018 4019 #undef TARGET_TRAMPOLINE_INIT 4020 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init 4021 4022 #undef TARGET_PROMOTE_FUNCTION_MODE 4023 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote 4024 4025 #undef TARGET_FUNCTION_VALUE 4026 #define TARGET_FUNCTION_VALUE microblaze_function_value 4027 4028 #undef TARGET_SECONDARY_RELOAD 4029 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload 4030 4031 #undef TARGET_ASM_OUTPUT_MI_THUNK 4032 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk 4033 4034 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK 4035 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true 4036 4037 #undef TARGET_SCHED_ADJUST_COST 4038 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost 4039 4040 #undef TARGET_ASM_INIT_SECTIONS 4041 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections 4042 4043 #undef TARGET_OPTION_OVERRIDE 4044 #define TARGET_OPTION_OVERRIDE microblaze_option_override 4045 4046 #undef TARGET_LEGITIMATE_CONSTANT_P 4047 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p 4048 4049 #undef TARGET_ASM_GENERATE_PIC_ADDR_DIFF_VEC 4050 #define TARGET_ASM_GENERATE_PIC_ADDR_DIFF_VEC microblaze_gen_pic_addr_dif_vec 4051 4052 #undef TARGET_MACHINE_DEPENDENT_REORG 4053 #define TARGET_MACHINE_DEPENDENT_REORG microblaze_machine_dependent_reorg 4054 4055 #undef TARGET_HARD_REGNO_MODE_OK 4056 #define TARGET_HARD_REGNO_MODE_OK microblaze_hard_regno_mode_ok 4057 4058 #undef TARGET_MODES_TIEABLE_P 4059 #define TARGET_MODES_TIEABLE_P microblaze_modes_tieable_p 4060 4061 #undef TARGET_CONSTANT_ALIGNMENT 4062 #define TARGET_CONSTANT_ALIGNMENT microblaze_constant_alignment 4063 4064 #undef TARGET_STARTING_FRAME_OFFSET 4065 #define TARGET_STARTING_FRAME_OFFSET microblaze_starting_frame_offset 4066 4067 struct gcc_target targetm = TARGET_INITIALIZER; 4068 4069 #include "gt-microblaze.h" 4070