1/* Subroutines used for code generation on the EPIPHANY cpu. 2 Copyright (C) 1994-2015 Free Software Foundation, Inc. 3 Contributed by Embecosm on behalf of Adapteva, Inc. 4 5This file is part of GCC. 6 7GCC is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 3, or (at your option) 10any later version. 11 12GCC is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with GCC; see the file COPYING3. If not see 19<http://www.gnu.org/licenses/>. */ 20 21#include "config.h" 22#include "system.h" 23#include "coretypes.h" 24#include "tm.h" 25#include "hash-set.h" 26#include "machmode.h" 27#include "vec.h" 28#include "double-int.h" 29#include "input.h" 30#include "alias.h" 31#include "symtab.h" 32#include "wide-int.h" 33#include "inchash.h" 34#include "tree.h" 35#include "fold-const.h" 36#include "stor-layout.h" 37#include "varasm.h" 38#include "calls.h" 39#include "stringpool.h" 40#include "rtl.h" 41#include "regs.h" 42#include "hard-reg-set.h" 43#include "real.h" 44#include "insn-config.h" 45#include "conditions.h" 46#include "output.h" 47#include "insn-attr.h" 48#include "flags.h" 49#include "function.h" 50#include "insn-codes.h" 51#include "optabs.h" 52#include "hashtab.h" 53#include "statistics.h" 54#include "fixed-value.h" 55#include "expmed.h" 56#include "dojump.h" 57#include "explow.h" 58#include "emit-rtl.h" 59#include "stmt.h" 60#include "expr.h" 61#include "diagnostic-core.h" 62#include "recog.h" 63#include "toplev.h" 64#include "tm_p.h" 65#include "target.h" 66#include "dominance.h" 67#include "cfg.h" 68#include "cfgrtl.h" 69#include "cfganal.h" 70#include "lcm.h" 71#include "cfgbuild.h" 72#include "cfgcleanup.h" 73#include "predict.h" 74#include "basic-block.h" 75#include "df.h" 76#include "langhooks.h" 77#include "ggc.h" 78#include "tm-constrs.h" 79#include "tree-pass.h" /* for current_pass */ 80#include "context.h" 81#include "pass_manager.h" 82#include "builtins.h" 83 84/* Which cpu we're compiling for. */ 85int epiphany_cpu_type; 86 87/* Name of mangle string to add to symbols to separate code compiled for each 88 cpu (or NULL). */ 89const char *epiphany_mangle_cpu; 90 91/* Array of valid operand punctuation characters. */ 92char epiphany_punct_chars[256]; 93 94/* The rounding mode that we generally use for floating point. */ 95int epiphany_normal_fp_rounding; 96 97/* The pass instance, for use in epiphany_optimize_mode_switching. */ 98static opt_pass *pass_mode_switch_use; 99 100static void epiphany_init_reg_tables (void); 101static int get_epiphany_condition_code (rtx); 102static tree epiphany_handle_interrupt_attribute (tree *, tree, tree, int, bool *); 103static tree epiphany_handle_forwarder_attribute (tree *, tree, tree, int, 104 bool *); 105static bool epiphany_pass_by_reference (cumulative_args_t, machine_mode, 106 const_tree, bool); 107static rtx_insn *frame_insn (rtx); 108 109/* defines for the initialization of the GCC target structure. */ 110#define TARGET_ATTRIBUTE_TABLE epiphany_attribute_table 111 112#define TARGET_PRINT_OPERAND epiphany_print_operand 113#define TARGET_PRINT_OPERAND_ADDRESS epiphany_print_operand_address 114 115#define TARGET_RTX_COSTS epiphany_rtx_costs 116#define TARGET_ADDRESS_COST epiphany_address_cost 117#define TARGET_MEMORY_MOVE_COST epiphany_memory_move_cost 118 119#define TARGET_PROMOTE_FUNCTION_MODE epiphany_promote_function_mode 120#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true 121 122#define TARGET_RETURN_IN_MEMORY epiphany_return_in_memory 123#define TARGET_PASS_BY_REFERENCE epiphany_pass_by_reference 124#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true 125#define TARGET_FUNCTION_VALUE epiphany_function_value 126#define TARGET_LIBCALL_VALUE epiphany_libcall_value 127#define TARGET_FUNCTION_VALUE_REGNO_P epiphany_function_value_regno_p 128 129#define TARGET_SETUP_INCOMING_VARARGS epiphany_setup_incoming_varargs 130 131/* Using the simplistic varags handling forces us to do partial reg/stack 132 argument passing for types with larger size (> 4 bytes) than alignemnt. */ 133#define TARGET_ARG_PARTIAL_BYTES epiphany_arg_partial_bytes 134 135#define TARGET_FUNCTION_OK_FOR_SIBCALL epiphany_function_ok_for_sibcall 136 137#define TARGET_SCHED_ISSUE_RATE epiphany_issue_rate 138#define TARGET_SCHED_ADJUST_COST epiphany_adjust_cost 139 140#define TARGET_LEGITIMATE_ADDRESS_P epiphany_legitimate_address_p 141 142#define TARGET_SECONDARY_RELOAD epiphany_secondary_reload 143 144#define TARGET_OPTION_OVERRIDE epiphany_override_options 145 146#define TARGET_CONDITIONAL_REGISTER_USAGE epiphany_conditional_register_usage 147 148#define TARGET_FUNCTION_ARG epiphany_function_arg 149 150#define TARGET_FUNCTION_ARG_ADVANCE epiphany_function_arg_advance 151 152#define TARGET_FUNCTION_ARG_BOUNDARY epiphany_function_arg_boundary 153 154#define TARGET_TRAMPOLINE_INIT epiphany_trampoline_init 155 156/* Nonzero if the constant rtx value is a legitimate general operand. 157 We can handle any 32- or 64-bit constant. */ 158#define TARGET_LEGITIMATE_CONSTANT_P hook_bool_mode_rtx_true 159 160#define TARGET_MIN_DIVISIONS_FOR_RECIP_MUL \ 161 epiphany_min_divisions_for_recip_mul 162 163#define TARGET_VECTORIZE_PREFERRED_SIMD_MODE epiphany_preferred_simd_mode 164 165#define TARGET_VECTOR_MODE_SUPPORTED_P epiphany_vector_mode_supported_p 166 167#define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE \ 168 epiphany_vector_alignment_reachable 169 170#define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \ 171 epiphany_support_vector_misalignment 172 173#define TARGET_ASM_CAN_OUTPUT_MI_THUNK \ 174 hook_bool_const_tree_hwi_hwi_const_tree_true 175#define TARGET_ASM_OUTPUT_MI_THUNK epiphany_output_mi_thunk 176 177/* ??? we can use larger offsets for wider-mode sized accesses, but there 178 is no concept of anchors being dependent on the modes that they are used 179 for, so we can only use an offset range that would suit all modes. */ 180#define TARGET_MAX_ANCHOR_OFFSET (optimize_size ? 31 : 2047) 181/* We further restrict the minimum to be a multiple of eight. */ 182#define TARGET_MIN_ANCHOR_OFFSET (optimize_size ? 0 : -2040) 183 184/* Mode switching hooks. */ 185 186#define TARGET_MODE_EMIT emit_set_fp_mode 187 188#define TARGET_MODE_NEEDED epiphany_mode_needed 189 190#define TARGET_MODE_PRIORITY epiphany_mode_priority 191 192#define TARGET_MODE_ENTRY epiphany_mode_entry 193 194#define TARGET_MODE_EXIT epiphany_mode_exit 195 196#define TARGET_MODE_AFTER epiphany_mode_after 197 198#include "target-def.h" 199 200#undef TARGET_ASM_ALIGNED_HI_OP 201#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t" 202#undef TARGET_ASM_ALIGNED_SI_OP 203#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" 204 205bool 206epiphany_is_interrupt_p (tree decl) 207{ 208 tree attrs; 209 210 attrs = DECL_ATTRIBUTES (decl); 211 if (lookup_attribute ("interrupt", attrs)) 212 return true; 213 else 214 return false; 215} 216 217/* Called from epiphany_override_options. 218 We use this to initialize various things. */ 219 220static void 221epiphany_init (void) 222{ 223 /* N.B. this pass must not run before the first optimize_mode_switching 224 pass because of the side offect of epiphany_mode_needed on 225 MACHINE_FUNCTION(cfun)->unknown_mode_uses. But it must run before 226 pass_resolve_sw_modes. */ 227 pass_mode_switch_use = make_pass_mode_switch_use (g); 228 struct register_pass_info insert_use_info 229 = { pass_mode_switch_use, "mode_sw", 230 1, PASS_POS_INSERT_AFTER 231 }; 232 opt_pass *mode_sw2 233 = g->get_passes()->get_pass_mode_switching ()->clone (); 234 struct register_pass_info mode_sw2_info 235 = { mode_sw2, "mode_sw", 236 1, PASS_POS_INSERT_AFTER 237 }; 238 opt_pass *mode_sw3 = make_pass_resolve_sw_modes (g); 239 struct register_pass_info mode_sw3_info 240 = { mode_sw3, "mode_sw", 241 1, PASS_POS_INSERT_AFTER 242 }; 243 opt_pass *mode_sw4 244 = g->get_passes()->get_pass_split_all_insns ()->clone (); 245 struct register_pass_info mode_sw4_info 246 = { mode_sw4, "mode_sw", 247 1, PASS_POS_INSERT_AFTER 248 }; 249 static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING; 250#define N_ENTITIES ARRAY_SIZE (num_modes) 251 252 epiphany_init_reg_tables (); 253 254 /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */ 255 memset (epiphany_punct_chars, 0, sizeof (epiphany_punct_chars)); 256 epiphany_punct_chars['-'] = 1; 257 258 epiphany_normal_fp_rounding 259 = (epiphany_normal_fp_mode == FP_MODE_ROUND_TRUNC 260 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST); 261 register_pass (&mode_sw4_info); 262 register_pass (&mode_sw2_info); 263 register_pass (&mode_sw3_info); 264 register_pass (&insert_use_info); 265 register_pass (&mode_sw2_info); 266 /* Verify that NUM_MODES_FOR_MODE_SWITCHING has one value per entity. */ 267 gcc_assert (N_ENTITIES == EPIPHANY_MSW_ENTITY_NUM); 268 269#if 1 /* As long as peep2_rescan is not implemented, 270 (see http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html,) 271 we need a second peephole2 pass to get reasonable code. */ 272 { 273 opt_pass *extra_peephole2 274 = g->get_passes ()->get_pass_peephole2 ()->clone (); 275 struct register_pass_info peep2_2_info 276 = { extra_peephole2, "peephole2", 277 1, PASS_POS_INSERT_AFTER 278 }; 279 280 register_pass (&peep2_2_info); 281 } 282#endif 283} 284 285/* The condition codes of the EPIPHANY, and the inverse function. */ 286static const char *const epiphany_condition_codes[] = 287{ /* 0 1 2 3 4 5 6 7 8 9 */ 288 "eq", "ne", "ltu", "gteu", "gt", "lte", "gte", "lt", "gtu", "lteu", 289 /* 10 11 12 13 */ 290 "beq","bne","blt", "blte", 291}; 292 293#define EPIPHANY_INVERSE_CONDITION_CODE(X) ((X) ^ 1) 294 295/* Returns the index of the EPIPHANY condition code string in 296 `epiphany_condition_codes'. COMPARISON should be an rtx like 297 `(eq (...) (...))'. */ 298 299static int 300get_epiphany_condition_code (rtx comparison) 301{ 302 switch (GET_MODE (XEXP (comparison, 0))) 303 { 304 case CCmode: 305 switch (GET_CODE (comparison)) 306 { 307 case EQ : return 0; 308 case NE : return 1; 309 case LTU : return 2; 310 case GEU : return 3; 311 case GT : return 4; 312 case LE : return 5; 313 case GE : return 6; 314 case LT : return 7; 315 case GTU : return 8; 316 case LEU : return 9; 317 318 default : gcc_unreachable (); 319 } 320 case CC_N_NEmode: 321 switch (GET_CODE (comparison)) 322 { 323 case EQ: return 6; 324 case NE: return 7; 325 default: gcc_unreachable (); 326 } 327 case CC_C_LTUmode: 328 switch (GET_CODE (comparison)) 329 { 330 case GEU: return 2; 331 case LTU: return 3; 332 default: gcc_unreachable (); 333 } 334 case CC_C_GTUmode: 335 switch (GET_CODE (comparison)) 336 { 337 case LEU: return 3; 338 case GTU: return 2; 339 default: gcc_unreachable (); 340 } 341 case CC_FPmode: 342 switch (GET_CODE (comparison)) 343 { 344 case EQ: return 10; 345 case NE: return 11; 346 case LT: return 12; 347 case LE: return 13; 348 default: gcc_unreachable (); 349 } 350 case CC_FP_EQmode: 351 switch (GET_CODE (comparison)) 352 { 353 case EQ: return 0; 354 case NE: return 1; 355 default: gcc_unreachable (); 356 } 357 case CC_FP_GTEmode: 358 switch (GET_CODE (comparison)) 359 { 360 case EQ: return 0; 361 case NE: return 1; 362 case GT : return 4; 363 case GE : return 6; 364 case UNLE : return 5; 365 case UNLT : return 7; 366 default: gcc_unreachable (); 367 } 368 case CC_FP_ORDmode: 369 switch (GET_CODE (comparison)) 370 { 371 case ORDERED: return 9; 372 case UNORDERED: return 8; 373 default: gcc_unreachable (); 374 } 375 case CC_FP_UNEQmode: 376 switch (GET_CODE (comparison)) 377 { 378 case UNEQ: return 9; 379 case LTGT: return 8; 380 default: gcc_unreachable (); 381 } 382 default: gcc_unreachable (); 383 } 384 /*NOTREACHED*/ 385 return (42); 386} 387 388 389/* Return 1 if hard register REGNO can hold a value of machine_mode MODE. */ 390int 391hard_regno_mode_ok (int regno, machine_mode mode) 392{ 393 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) 394 return (regno & 1) == 0 && GPR_P (regno); 395 else 396 return 1; 397} 398 399/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, 400 return the mode to be used for the comparison. */ 401 402machine_mode 403epiphany_select_cc_mode (enum rtx_code op, 404 rtx x ATTRIBUTE_UNUSED, 405 rtx y ATTRIBUTE_UNUSED) 406{ 407 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) 408 { 409 if (TARGET_SOFT_CMPSF 410 || op == ORDERED || op == UNORDERED) 411 { 412 if (op == EQ || op == NE) 413 return CC_FP_EQmode; 414 if (op == ORDERED || op == UNORDERED) 415 return CC_FP_ORDmode; 416 if (op == UNEQ || op == LTGT) 417 return CC_FP_UNEQmode; 418 return CC_FP_GTEmode; 419 } 420 return CC_FPmode; 421 } 422 /* recognize combiner pattern ashlsi_btst: 423 (parallel [ 424 (set (reg:N_NE 65 cc1) 425 (compare:N_NE (zero_extract:SI (reg/v:SI 75 [ a ]) 426 (const_int 1 [0x1]) 427 (const_int 0 [0x0])) 428 (const_int 0 [0x0]))) 429 (clobber (scratch:SI)) */ 430 else if ((op == EQ || op == NE) 431 && GET_CODE (x) == ZERO_EXTRACT 432 && XEXP (x, 1) == const1_rtx 433 && CONST_INT_P (XEXP (x, 2))) 434 return CC_N_NEmode; 435 else if ((op == GEU || op == LTU) && GET_CODE (x) == PLUS) 436 return CC_C_LTUmode; 437 else if ((op == LEU || op == GTU) && GET_CODE (x) == MINUS) 438 return CC_C_GTUmode; 439 else 440 return CCmode; 441} 442 443enum reg_class epiphany_regno_reg_class[FIRST_PSEUDO_REGISTER]; 444 445static void 446epiphany_init_reg_tables (void) 447{ 448 int i; 449 450 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 451 { 452 if (i == GPR_LR) 453 epiphany_regno_reg_class[i] = LR_REGS; 454 else if (i <= 7 && TARGET_PREFER_SHORT_INSN_REGS) 455 epiphany_regno_reg_class[i] = SHORT_INSN_REGS; 456 else if (call_used_regs[i] 457 && TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i)) 458 epiphany_regno_reg_class[i] = SIBCALL_REGS; 459 else if (i >= CORE_CONTROL_FIRST && i <= CORE_CONTROL_LAST) 460 epiphany_regno_reg_class[i] = CORE_CONTROL_REGS; 461 else if (i < (GPR_LAST+1) 462 || i == ARG_POINTER_REGNUM || i == FRAME_POINTER_REGNUM) 463 epiphany_regno_reg_class[i] = GENERAL_REGS; 464 else if (i == CC_REGNUM) 465 epiphany_regno_reg_class[i] = NO_REGS /* CC_REG: must be NO_REGS */; 466 else 467 epiphany_regno_reg_class[i] = NO_REGS; 468 } 469} 470 471/* EPIPHANY specific attribute support. 472 473 The EPIPHANY has these attributes: 474 interrupt - for interrupt functions. 475 short_call - the function is assumed to be reachable with the b / bl 476 instructions. 477 long_call - the function address is loaded into a register before use. 478 disinterrupt - functions which mask interrupts throughout. 479 They unmask them while calling an interruptible 480 function, though. */ 481 482static const struct attribute_spec epiphany_attribute_table[] = 483{ 484 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ 485 { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true }, 486 { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false }, 487 { "long_call", 0, 0, false, true, true, NULL, false }, 488 { "short_call", 0, 0, false, true, true, NULL, false }, 489 { "disinterrupt", 0, 0, false, true, true, NULL, true }, 490 { NULL, 0, 0, false, false, false, NULL, false } 491}; 492 493/* Handle an "interrupt" attribute; arguments as in 494 struct attribute_spec.handler. */ 495static tree 496epiphany_handle_interrupt_attribute (tree *node, tree name, tree args, 497 int flags ATTRIBUTE_UNUSED, 498 bool *no_add_attrs) 499{ 500 tree value; 501 502 if (!args) 503 { 504 gcc_assert (DECL_P (*node)); 505 tree t = TREE_TYPE (*node); 506 if (TREE_CODE (t) != FUNCTION_TYPE) 507 warning (OPT_Wattributes, "%qE attribute only applies to functions", 508 name); 509 /* Argument handling and the stack layout for interrupt handlers 510 don't mix. It makes no sense in the first place, so emit an 511 error for this. */ 512 else if (TYPE_ARG_TYPES (t) 513 && TREE_VALUE (TYPE_ARG_TYPES (t)) != void_type_node) 514 error_at (DECL_SOURCE_LOCATION (*node), 515 "interrupt handlers cannot have arguments"); 516 return NULL_TREE; 517 } 518 519 value = TREE_VALUE (args); 520 521 if (TREE_CODE (value) != STRING_CST) 522 { 523 warning (OPT_Wattributes, 524 "argument of %qE attribute is not a string constant", name); 525 *no_add_attrs = true; 526 } 527 else if (strcmp (TREE_STRING_POINTER (value), "reset") 528 && strcmp (TREE_STRING_POINTER (value), "software_exception") 529 && strcmp (TREE_STRING_POINTER (value), "page_miss") 530 && strcmp (TREE_STRING_POINTER (value), "timer0") 531 && strcmp (TREE_STRING_POINTER (value), "timer1") 532 && strcmp (TREE_STRING_POINTER (value), "message") 533 && strcmp (TREE_STRING_POINTER (value), "dma0") 534 && strcmp (TREE_STRING_POINTER (value), "dma1") 535 && strcmp (TREE_STRING_POINTER (value), "wand") 536 && strcmp (TREE_STRING_POINTER (value), "swi")) 537 { 538 warning (OPT_Wattributes, 539 "argument of %qE attribute is not \"reset\", \"software_exception\", \"page_miss\", \"timer0\", \"timer1\", \"message\", \"dma0\", \"dma1\", \"wand\" or \"swi\"", 540 name); 541 *no_add_attrs = true; 542 return NULL_TREE; 543 } 544 545 return epiphany_handle_interrupt_attribute (node, name, TREE_CHAIN (args), 546 flags, no_add_attrs); 547} 548 549/* Handle a "forwarder_section" attribute; arguments as in 550 struct attribute_spec.handler. */ 551static tree 552epiphany_handle_forwarder_attribute (tree *node ATTRIBUTE_UNUSED, 553 tree name, tree args, 554 int flags ATTRIBUTE_UNUSED, 555 bool *no_add_attrs) 556{ 557 tree value; 558 559 value = TREE_VALUE (args); 560 561 if (TREE_CODE (value) != STRING_CST) 562 { 563 warning (OPT_Wattributes, 564 "argument of %qE attribute is not a string constant", name); 565 *no_add_attrs = true; 566 } 567 return NULL_TREE; 568} 569 570 571/* Misc. utilities. */ 572 573/* Generate a SYMBOL_REF for the special function NAME. When the address 574 can't be placed directly into a call instruction, and if possible, copy 575 it to a register so that cse / code hoisting is possible. */ 576rtx 577sfunc_symbol (const char *name) 578{ 579 rtx sym = gen_rtx_SYMBOL_REF (Pmode, name); 580 581 /* These sfuncs should be hidden, and every dso should get a copy. */ 582 SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_FUNCTION | SYMBOL_FLAG_LOCAL; 583 if (TARGET_SHORT_CALLS) 584 ; /* Nothing to be done. */ 585 else if (can_create_pseudo_p ()) 586 sym = copy_to_mode_reg (Pmode, sym); 587 else /* We rely on reload to fix this up. */ 588 gcc_assert (!reload_in_progress || reload_completed); 589 return sym; 590} 591 592/* X and Y are two things to compare using CODE in IN_MODE. 593 Emit the compare insn, construct the the proper cc reg in the proper 594 mode, and return the rtx for the cc reg comparison in CMODE. */ 595 596rtx 597gen_compare_reg (machine_mode cmode, enum rtx_code code, 598 machine_mode in_mode, rtx x, rtx y) 599{ 600 machine_mode mode = SELECT_CC_MODE (code, x, y); 601 rtx cc_reg, pat, clob0, clob1, clob2; 602 603 if (in_mode == VOIDmode) 604 in_mode = GET_MODE (x); 605 if (in_mode == VOIDmode) 606 in_mode = GET_MODE (y); 607 608 if (mode == CC_FPmode) 609 { 610 /* The epiphany has only EQ / NE / LT / LE conditions for 611 hardware floating point. */ 612 if (code == GT || code == GE || code == UNLE || code == UNLT) 613 { 614 rtx tmp = x; x = y; y = tmp; 615 code = swap_condition (code); 616 } 617 cc_reg = gen_rtx_REG (mode, CCFP_REGNUM); 618 y = force_reg (in_mode, y); 619 } 620 else 621 { 622 if (mode == CC_FP_GTEmode 623 && (code == LE || code == LT || code == UNGT || code == UNGE)) 624 { 625 if (flag_finite_math_only 626 && ((REG_P (x) && REGNO (x) == GPR_0) 627 || (REG_P (y) && REGNO (y) == GPR_1))) 628 switch (code) 629 { 630 case LE: code = UNLE; break; 631 case LT: code = UNLT; break; 632 case UNGT: code = GT; break; 633 case UNGE: code = GE; break; 634 default: gcc_unreachable (); 635 } 636 else 637 { 638 rtx tmp = x; x = y; y = tmp; 639 code = swap_condition (code); 640 } 641 } 642 cc_reg = gen_rtx_REG (mode, CC_REGNUM); 643 } 644 if ((mode == CC_FP_EQmode || mode == CC_FP_GTEmode 645 || mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode) 646 /* mov<mode>cc might want to re-emit a comparison during ifcvt. */ 647 && (!REG_P (x) || REGNO (x) != GPR_0 648 || !REG_P (y) || REGNO (y) != GPR_1)) 649 { 650 rtx reg; 651 652#if 0 653 /* ??? We should really do the r0/r1 clobber only during rtl expansion, 654 but just like the flag clobber of movsicc, we have to allow 655 this for ifcvt to work, on the assumption that we'll only want 656 to do this if these registers have been used before by the 657 pre-ifcvt code. */ 658 gcc_assert (currently_expanding_to_rtl); 659#endif 660 reg = gen_rtx_REG (in_mode, GPR_0); 661 if (reg_overlap_mentioned_p (reg, y)) 662 return 0; 663 emit_move_insn (reg, x); 664 x = reg; 665 reg = gen_rtx_REG (in_mode, GPR_1); 666 emit_move_insn (reg, y); 667 y = reg; 668 } 669 else 670 x = force_reg (in_mode, x); 671 672 pat = gen_rtx_SET (VOIDmode, cc_reg, gen_rtx_COMPARE (mode, x, y)); 673 if (mode == CC_FP_EQmode || mode == CC_FP_GTEmode) 674 { 675 const char *name = mode == CC_FP_EQmode ? "__eqsf2" : "__gtesf2"; 676 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name)); 677 678 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP)); 679 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR)); 680 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (4, pat, use, clob0, clob1)); 681 } 682 else if (mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode) 683 { 684 const char *name = mode == CC_FP_ORDmode ? "__ordsf2" : "__uneqsf2"; 685 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name)); 686 687 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP)); 688 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_16)); 689 clob2 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR)); 690 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (5, pat, use, 691 clob0, clob1, clob2)); 692 } 693 else 694 { 695 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (in_mode)); 696 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, pat, clob0)); 697 } 698 emit_insn (pat); 699 return gen_rtx_fmt_ee (code, cmode, cc_reg, const0_rtx); 700} 701 702/* The ROUND_ADVANCE* macros are local to this file. */ 703/* Round SIZE up to a word boundary. */ 704#define ROUND_ADVANCE(SIZE) \ 705 (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) 706 707/* Round arg MODE/TYPE up to the next word boundary. */ 708#define ROUND_ADVANCE_ARG(MODE, TYPE) \ 709 ((MODE) == BLKmode \ 710 ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \ 711 : ROUND_ADVANCE (GET_MODE_SIZE (MODE))) 712 713/* Round CUM up to the necessary point for argument MODE/TYPE. */ 714#define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \ 715 (epiphany_function_arg_boundary ((MODE), (TYPE)) > BITS_PER_WORD \ 716 ? (((CUM) + 1) & ~1) \ 717 : (CUM)) 718 719static unsigned int 720epiphany_function_arg_boundary (machine_mode mode, const_tree type) 721{ 722 if ((type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode)) <= PARM_BOUNDARY) 723 return PARM_BOUNDARY; 724 return 2 * PARM_BOUNDARY; 725} 726 727/* Do any needed setup for a variadic function. For the EPIPHANY, we 728 actually emit the code in epiphany_expand_prologue. 729 730 CUM has not been updated for the last named argument which has type TYPE 731 and mode MODE, and we rely on this fact. */ 732 733 734static void 735epiphany_setup_incoming_varargs (cumulative_args_t cum, machine_mode mode, 736 tree type, int *pretend_size, int no_rtl) 737{ 738 int first_anon_arg; 739 CUMULATIVE_ARGS next_cum; 740 machine_function_t *mf = MACHINE_FUNCTION (cfun); 741 742 /* All BLKmode values are passed by reference. */ 743 gcc_assert (mode != BLKmode); 744 745 next_cum = *get_cumulative_args (cum); 746 next_cum 747 = ROUND_ADVANCE_CUM (next_cum, mode, type) + ROUND_ADVANCE_ARG (mode, type); 748 first_anon_arg = next_cum; 749 750 if (first_anon_arg < MAX_EPIPHANY_PARM_REGS && !no_rtl) 751 { 752 /* Note that first_reg_offset < MAX_EPIPHANY_PARM_REGS. */ 753 int first_reg_offset = first_anon_arg; 754 755 *pretend_size = ((MAX_EPIPHANY_PARM_REGS - first_reg_offset) 756 * UNITS_PER_WORD); 757 } 758 mf->args_parsed = 1; 759 mf->pretend_args_odd = ((*pretend_size & UNITS_PER_WORD) ? 1 : 0); 760} 761 762static int 763epiphany_arg_partial_bytes (cumulative_args_t cum, machine_mode mode, 764 tree type, bool named ATTRIBUTE_UNUSED) 765{ 766 int words = 0, rounded_cum; 767 768 gcc_assert (!epiphany_pass_by_reference (cum, mode, type, /* named */ true)); 769 770 rounded_cum = ROUND_ADVANCE_CUM (*get_cumulative_args (cum), mode, type); 771 if (rounded_cum < MAX_EPIPHANY_PARM_REGS) 772 { 773 words = MAX_EPIPHANY_PARM_REGS - rounded_cum; 774 if (words >= ROUND_ADVANCE_ARG (mode, type)) 775 words = 0; 776 } 777 return words * UNITS_PER_WORD; 778} 779 780/* Cost functions. */ 781 782/* Compute a (partial) cost for rtx X. Return true if the complete 783 cost has been computed, and false if subexpressions should be 784 scanned. In either case, *TOTAL contains the cost result. */ 785 786static bool 787epiphany_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED, 788 int *total, bool speed ATTRIBUTE_UNUSED) 789{ 790 switch (code) 791 { 792 /* Small integers in the right context are as cheap as registers. */ 793 case CONST_INT: 794 if ((outer_code == PLUS || outer_code == MINUS) 795 && SIMM11 (INTVAL (x))) 796 { 797 *total = 0; 798 return true; 799 } 800 if (IMM16 (INTVAL (x))) 801 { 802 *total = outer_code == SET ? 0 : COSTS_N_INSNS (1); 803 return true; 804 } 805 /* FALLTHRU */ 806 807 case CONST: 808 case LABEL_REF: 809 case SYMBOL_REF: 810 *total = COSTS_N_INSNS ((epiphany_small16 (x) ? 0 : 1) 811 + (outer_code == SET ? 0 : 1)); 812 return true; 813 814 case CONST_DOUBLE: 815 { 816 rtx high, low; 817 split_double (x, &high, &low); 818 *total = COSTS_N_INSNS (!IMM16 (INTVAL (high)) 819 + !IMM16 (INTVAL (low))); 820 return true; 821 } 822 823 case ASHIFT: 824 case ASHIFTRT: 825 case LSHIFTRT: 826 *total = COSTS_N_INSNS (1); 827 return true; 828 829 case COMPARE: 830 switch (GET_MODE (x)) 831 { 832 /* There are a number of single-insn combiner patterns that use 833 the flag side effects of arithmetic. */ 834 case CC_N_NEmode: 835 case CC_C_LTUmode: 836 case CC_C_GTUmode: 837 return true; 838 default: 839 return false; 840 } 841 842 843 case SET: 844 { 845 rtx src = SET_SRC (x); 846 if (BINARY_P (src)) 847 *total = 0; 848 return false; 849 } 850 851 default: 852 return false; 853 } 854} 855 856 857/* Provide the costs of an addressing mode that contains ADDR. 858 If ADDR is not a valid address, its cost is irrelevant. */ 859 860static int 861epiphany_address_cost (rtx addr, machine_mode mode, 862 addr_space_t as ATTRIBUTE_UNUSED, bool speed) 863{ 864 rtx reg; 865 rtx off = const0_rtx; 866 int i; 867 868 if (speed) 869 return 0; 870 /* Return 0 for addresses valid in short insns, 1 for addresses only valid 871 in long insns. */ 872 switch (GET_CODE (addr)) 873 { 874 case PLUS : 875 reg = XEXP (addr, 0); 876 off = XEXP (addr, 1); 877 break; 878 case POST_MODIFY: 879 reg = XEXP (addr, 0); 880 off = XEXP (addr, 1); 881 gcc_assert (GET_CODE (off) == PLUS && rtx_equal_p (reg, XEXP (off, 0))); 882 off = XEXP (off, 1); 883 if (satisfies_constraint_Rgs (reg) && satisfies_constraint_Rgs (off)) 884 return 0; 885 return 1; 886 case REG: 887 default: 888 reg = addr; 889 break; 890 } 891 if (!satisfies_constraint_Rgs (reg)) 892 return 1; 893 /* The offset range available for short instructions depends on the mode 894 of the memory access. */ 895 /* First, make sure we have a valid integer. */ 896 if (!satisfies_constraint_L (off)) 897 return 1; 898 i = INTVAL (off); 899 switch (GET_MODE_SIZE (mode)) 900 { 901 default: 902 case 4: 903 if (i & 1) 904 return 1; 905 i >>= 1; 906 /* Fall through. */ 907 case 2: 908 if (i & 1) 909 return 1; 910 i >>= 1; 911 /* Fall through. */ 912 case 1: 913 return i < -7 || i > 7; 914 } 915} 916 917/* Compute the cost of moving data between registers and memory. 918 For integer, load latency is twice as long as register-register moves, 919 but issue pich is the same. For floating point, load latency is three 920 times as much as a reg-reg move. */ 921static int 922epiphany_memory_move_cost (machine_mode mode, 923 reg_class_t rclass ATTRIBUTE_UNUSED, 924 bool in ATTRIBUTE_UNUSED) 925{ 926 return GET_MODE_CLASS (mode) == MODE_INT ? 3 : 4; 927} 928 929/* Function prologue/epilogue handlers. */ 930 931/* EPIPHANY stack frames look like: 932 933 Before call After call 934 +-----------------------+ +-----------------------+ 935 | | | | 936 high | local variables, | | local variables, | 937 mem | reg save area, etc. | | reg save area, etc. | 938 | | | | 939 +-----------------------+ +-----------------------+ 940 | | | | 941 | arguments on stack. | | arguments on stack. | 942 | | | | 943 SP+8->+-----------------------+FP+8m->+-----------------------+ 944 | 2 word save area for | | reg parm save area, | 945 | leaf funcs / flags | | only created for | 946 SP+0->+-----------------------+ | variable argument | 947 | functions | 948 FP+8n->+-----------------------+ 949 | | 950 | register save area | 951 | | 952 +-----------------------+ 953 | | 954 | local variables | 955 | | 956 FP+0->+-----------------------+ 957 | | 958 | alloca allocations | 959 | | 960 +-----------------------+ 961 | | 962 | arguments on stack | 963 | | 964 SP+8->+-----------------------+ 965 low | 2 word save area for | 966 memory | leaf funcs / flags | 967 SP+0->+-----------------------+ 968 969Notes: 9701) The "reg parm save area" does not exist for non variable argument fns. 971 The "reg parm save area" could be eliminated if we created our 972 own TARGET_GIMPLIFY_VA_ARG_EXPR, but that has tradeoffs as well 973 (so it's not done). */ 974 975/* Structure to be filled in by epiphany_compute_frame_size with register 976 save masks, and offsets for the current function. */ 977struct epiphany_frame_info 978{ 979 unsigned int total_size; /* # bytes that the entire frame takes up. */ 980 unsigned int pretend_size; /* # bytes we push and pretend caller did. */ 981 unsigned int args_size; /* # bytes that outgoing arguments take up. */ 982 unsigned int reg_size; /* # bytes needed to store regs. */ 983 unsigned int var_size; /* # bytes that variables take up. */ 984 HARD_REG_SET gmask; /* Set of saved gp registers. */ 985 int initialized; /* Nonzero if frame size already calculated. */ 986 int stld_sz; /* Current load/store data size for offset 987 adjustment. */ 988 int need_fp; /* value to override "frame_pointer_needed */ 989 /* FIRST_SLOT is the slot that is saved first, at the very start of 990 the frame, with a POST_MODIFY to allocate the frame, if the size fits, 991 or at least the parm and register save areas, otherwise. 992 In the case of a large frame, LAST_SLOT is the slot that is saved last, 993 with a POST_MODIFY to allocate the rest of the frame. */ 994 int first_slot, last_slot, first_slot_offset, last_slot_offset; 995 int first_slot_size; 996 int small_threshold; 997}; 998 999/* Current frame information calculated by epiphany_compute_frame_size. */ 1000static struct epiphany_frame_info current_frame_info; 1001 1002/* Zero structure to initialize current_frame_info. */ 1003static struct epiphany_frame_info zero_frame_info; 1004 1005/* The usual; we set up our machine_function data. */ 1006static struct machine_function * 1007epiphany_init_machine_status (void) 1008{ 1009 struct machine_function *machine; 1010 1011 /* Reset state info for each function. */ 1012 current_frame_info = zero_frame_info; 1013 1014 machine = ggc_cleared_alloc<machine_function_t> (); 1015 1016 return machine; 1017} 1018 1019/* Implements INIT_EXPANDERS. We just set up to call the above 1020 * function. */ 1021void 1022epiphany_init_expanders (void) 1023{ 1024 init_machine_status = epiphany_init_machine_status; 1025} 1026 1027/* Type of function DECL. 1028 1029 The result is cached. To reset the cache at the end of a function, 1030 call with DECL = NULL_TREE. */ 1031 1032static enum epiphany_function_type 1033epiphany_compute_function_type (tree decl) 1034{ 1035 tree a; 1036 /* Cached value. */ 1037 static enum epiphany_function_type fn_type = EPIPHANY_FUNCTION_UNKNOWN; 1038 /* Last function we were called for. */ 1039 static tree last_fn = NULL_TREE; 1040 1041 /* Resetting the cached value? */ 1042 if (decl == NULL_TREE) 1043 { 1044 fn_type = EPIPHANY_FUNCTION_UNKNOWN; 1045 last_fn = NULL_TREE; 1046 return fn_type; 1047 } 1048 1049 if (decl == last_fn && fn_type != EPIPHANY_FUNCTION_UNKNOWN) 1050 return fn_type; 1051 1052 /* Assume we have a normal function (not an interrupt handler). */ 1053 fn_type = EPIPHANY_FUNCTION_NORMAL; 1054 1055 /* Now see if this is an interrupt handler. */ 1056 for (a = DECL_ATTRIBUTES (decl); 1057 a; 1058 a = TREE_CHAIN (a)) 1059 { 1060 tree name = TREE_PURPOSE (a); 1061 1062 if (name == get_identifier ("interrupt")) 1063 fn_type = EPIPHANY_FUNCTION_INTERRUPT; 1064 } 1065 1066 last_fn = decl; 1067 return fn_type; 1068} 1069 1070#define RETURN_ADDR_REGNUM GPR_LR 1071#define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM)) 1072#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM)) 1073 1074/* Tell prologue and epilogue if register REGNO should be saved / restored. 1075 The return address and frame pointer are treated separately. 1076 Don't consider them here. */ 1077#define MUST_SAVE_REGISTER(regno, interrupt_p) \ 1078 ((df_regs_ever_live_p (regno) \ 1079 || (interrupt_p && !crtl->is_leaf \ 1080 && call_used_regs[regno] && !fixed_regs[regno])) \ 1081 && (!call_used_regs[regno] || regno == GPR_LR \ 1082 || (interrupt_p && regno != GPR_SP))) 1083 1084#define MUST_SAVE_RETURN_ADDR 0 1085 1086/* Return the bytes needed to compute the frame pointer from the current 1087 stack pointer. 1088 1089 SIZE is the size needed for local variables. */ 1090 1091static unsigned int 1092epiphany_compute_frame_size (int size /* # of var. bytes allocated. */) 1093{ 1094 int regno; 1095 unsigned int total_size, var_size, args_size, pretend_size, reg_size; 1096 HARD_REG_SET gmask; 1097 enum epiphany_function_type fn_type; 1098 int interrupt_p; 1099 int first_slot, last_slot, first_slot_offset, last_slot_offset; 1100 int first_slot_size; 1101 int small_slots = 0; 1102 1103 var_size = size; 1104 args_size = crtl->outgoing_args_size; 1105 pretend_size = crtl->args.pretend_args_size; 1106 total_size = args_size + var_size; 1107 reg_size = 0; 1108 CLEAR_HARD_REG_SET (gmask); 1109 first_slot = -1; 1110 first_slot_offset = 0; 1111 last_slot = -1; 1112 last_slot_offset = 0; 1113 first_slot_size = UNITS_PER_WORD; 1114 1115 /* See if this is an interrupt handler. Call used registers must be saved 1116 for them too. */ 1117 fn_type = epiphany_compute_function_type (current_function_decl); 1118 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type); 1119 1120 /* Calculate space needed for registers. */ 1121 1122 for (regno = MAX_EPIPHANY_PARM_REGS - 1; pretend_size > reg_size; regno--) 1123 { 1124 reg_size += UNITS_PER_WORD; 1125 SET_HARD_REG_BIT (gmask, regno); 1126 if (epiphany_stack_offset - reg_size == 0) 1127 first_slot = regno; 1128 } 1129 1130 if (interrupt_p) 1131 reg_size += 2 * UNITS_PER_WORD; 1132 else 1133 small_slots = epiphany_stack_offset / UNITS_PER_WORD; 1134 1135 if (frame_pointer_needed) 1136 { 1137 current_frame_info.need_fp = 1; 1138 if (!interrupt_p && first_slot < 0) 1139 first_slot = GPR_FP; 1140 } 1141 else 1142 current_frame_info.need_fp = 0; 1143 for (regno = 0; regno <= GPR_LAST; regno++) 1144 { 1145 if (MUST_SAVE_REGISTER (regno, interrupt_p)) 1146 { 1147 gcc_assert (!TEST_HARD_REG_BIT (gmask, regno)); 1148 reg_size += UNITS_PER_WORD; 1149 SET_HARD_REG_BIT (gmask, regno); 1150 /* FIXME: when optimizing for speed, take schedling into account 1151 when selecting these registers. */ 1152 if (regno == first_slot) 1153 gcc_assert (regno == GPR_FP && frame_pointer_needed); 1154 else if (!interrupt_p && first_slot < 0) 1155 first_slot = regno; 1156 else if (last_slot < 0 1157 && (first_slot ^ regno) != 1 1158 && (!interrupt_p || regno > GPR_1)) 1159 last_slot = regno; 1160 } 1161 } 1162 if (TEST_HARD_REG_BIT (gmask, GPR_LR)) 1163 MACHINE_FUNCTION (cfun)->lr_clobbered = 1; 1164 /* ??? Could sometimes do better than that. */ 1165 current_frame_info.small_threshold 1166 = (optimize >= 3 || interrupt_p ? 0 1167 : pretend_size ? small_slots 1168 : 4 + small_slots - (first_slot == GPR_FP)); 1169 1170 /* If there might be variables with 64-bit alignment requirement, align the 1171 start of the variables. */ 1172 if (var_size >= 2 * UNITS_PER_WORD 1173 /* We don't want to split a double reg save/restore across two unpaired 1174 stack slots when optimizing. This rounding could be avoided with 1175 more complex reordering of the register saves, but that would seem 1176 to be a lot of code complexity for little gain. */ 1177 || (reg_size > 8 && optimize)) 1178 reg_size = EPIPHANY_STACK_ALIGN (reg_size); 1179 if (((total_size + reg_size 1180 /* Reserve space for UNKNOWN_REGNUM. */ 1181 + EPIPHANY_STACK_ALIGN (4)) 1182 <= (unsigned) epiphany_stack_offset) 1183 && !interrupt_p 1184 && crtl->is_leaf && !frame_pointer_needed) 1185 { 1186 first_slot = -1; 1187 last_slot = -1; 1188 goto alloc_done; 1189 } 1190 else if (reg_size 1191 && !interrupt_p 1192 && reg_size < (unsigned HOST_WIDE_INT) epiphany_stack_offset) 1193 reg_size = epiphany_stack_offset; 1194 if (interrupt_p) 1195 { 1196 if (total_size + reg_size < 0x3fc) 1197 { 1198 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size); 1199 first_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset); 1200 last_slot = -1; 1201 } 1202 else 1203 { 1204 first_slot_offset = EPIPHANY_STACK_ALIGN (reg_size); 1205 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size); 1206 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset); 1207 if (last_slot >= 0) 1208 CLEAR_HARD_REG_BIT (gmask, last_slot); 1209 } 1210 } 1211 else if (total_size + reg_size < 0x1ffc && first_slot >= 0) 1212 { 1213 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size); 1214 last_slot = -1; 1215 } 1216 else 1217 { 1218 if (total_size + reg_size <= (unsigned) epiphany_stack_offset) 1219 { 1220 gcc_assert (first_slot < 0); 1221 gcc_assert (reg_size == 0 || (int) reg_size == epiphany_stack_offset); 1222 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size); 1223 } 1224 else 1225 { 1226 first_slot_offset 1227 = (reg_size 1228 ? EPIPHANY_STACK_ALIGN (reg_size - epiphany_stack_offset) : 0); 1229 if (!first_slot_offset) 1230 { 1231 if (first_slot != GPR_FP || !current_frame_info.need_fp) 1232 last_slot = first_slot; 1233 first_slot = -1; 1234 } 1235 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size); 1236 if (reg_size) 1237 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset); 1238 } 1239 if (last_slot >= 0) 1240 CLEAR_HARD_REG_BIT (gmask, last_slot); 1241 } 1242 alloc_done: 1243 if (first_slot >= 0) 1244 { 1245 CLEAR_HARD_REG_BIT (gmask, first_slot); 1246 if (TEST_HARD_REG_BIT (gmask, first_slot ^ 1) 1247 && epiphany_stack_offset - pretend_size >= 2 * UNITS_PER_WORD) 1248 { 1249 CLEAR_HARD_REG_BIT (gmask, first_slot ^ 1); 1250 first_slot_size = 2 * UNITS_PER_WORD; 1251 first_slot &= ~1; 1252 } 1253 } 1254 total_size = first_slot_offset + last_slot_offset; 1255 1256 /* Save computed information. */ 1257 current_frame_info.total_size = total_size; 1258 current_frame_info.pretend_size = pretend_size; 1259 current_frame_info.var_size = var_size; 1260 current_frame_info.args_size = args_size; 1261 current_frame_info.reg_size = reg_size; 1262 COPY_HARD_REG_SET (current_frame_info.gmask, gmask); 1263 current_frame_info.first_slot = first_slot; 1264 current_frame_info.last_slot = last_slot; 1265 current_frame_info.first_slot_offset = first_slot_offset; 1266 current_frame_info.first_slot_size = first_slot_size; 1267 current_frame_info.last_slot_offset = last_slot_offset; 1268 1269 current_frame_info.initialized = reload_completed; 1270 1271 /* Ok, we're done. */ 1272 return total_size; 1273} 1274 1275/* Print operand X (an rtx) in assembler syntax to file FILE. 1276 CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. 1277 For `%' followed by punctuation, CODE is the punctuation and X is null. */ 1278 1279static void 1280epiphany_print_operand (FILE *file, rtx x, int code) 1281{ 1282 switch (code) 1283 { 1284 case 'd': 1285 fputs (epiphany_condition_codes[get_epiphany_condition_code (x)], file); 1286 return; 1287 case 'D': 1288 fputs (epiphany_condition_codes[EPIPHANY_INVERSE_CONDITION_CODE 1289 (get_epiphany_condition_code (x))], 1290 file); 1291 return; 1292 1293 case 'X': 1294 current_frame_info.stld_sz = 8; 1295 break; 1296 1297 case 'C' : 1298 current_frame_info.stld_sz = 4; 1299 break; 1300 1301 case 'c' : 1302 current_frame_info.stld_sz = 2; 1303 break; 1304 1305 case 'f': 1306 fputs (REG_P (x) ? "jalr " : "bl ", file); 1307 break; 1308 1309 case '-': 1310 fprintf (file, "r%d", epiphany_m1reg); 1311 return; 1312 1313 case 0 : 1314 /* Do nothing special. */ 1315 break; 1316 default : 1317 /* Unknown flag. */ 1318 output_operand_lossage ("invalid operand output code"); 1319 } 1320 1321 switch (GET_CODE (x)) 1322 { 1323 rtx addr; 1324 rtx offset; 1325 1326 case REG : 1327 fputs (reg_names[REGNO (x)], file); 1328 break; 1329 case MEM : 1330 if (code == 0) 1331 current_frame_info.stld_sz = 1; 1332 fputc ('[', file); 1333 addr = XEXP (x, 0); 1334 switch (GET_CODE (addr)) 1335 { 1336 case POST_INC: 1337 offset = GEN_INT (GET_MODE_SIZE (GET_MODE (x))); 1338 addr = XEXP (addr, 0); 1339 break; 1340 case POST_DEC: 1341 offset = GEN_INT (-GET_MODE_SIZE (GET_MODE (x))); 1342 addr = XEXP (addr, 0); 1343 break; 1344 case POST_MODIFY: 1345 offset = XEXP (XEXP (addr, 1), 1); 1346 addr = XEXP (addr, 0); 1347 break; 1348 default: 1349 offset = 0; 1350 break; 1351 } 1352 output_address (addr); 1353 fputc (']', file); 1354 if (offset) 1355 { 1356 fputc (',', file); 1357 if (CONST_INT_P (offset)) switch (GET_MODE_SIZE (GET_MODE (x))) 1358 { 1359 default: 1360 gcc_unreachable (); 1361 case 8: 1362 offset = GEN_INT (INTVAL (offset) >> 3); 1363 break; 1364 case 4: 1365 offset = GEN_INT (INTVAL (offset) >> 2); 1366 break; 1367 case 2: 1368 offset = GEN_INT (INTVAL (offset) >> 1); 1369 break; 1370 case 1: 1371 break; 1372 } 1373 output_address (offset); 1374 } 1375 break; 1376 case CONST_DOUBLE : 1377 /* We handle SFmode constants here as output_addr_const doesn't. */ 1378 if (GET_MODE (x) == SFmode) 1379 { 1380 REAL_VALUE_TYPE d; 1381 long l; 1382 1383 REAL_VALUE_FROM_CONST_DOUBLE (d, x); 1384 REAL_VALUE_TO_TARGET_SINGLE (d, l); 1385 fprintf (file, "%s0x%08lx", IMMEDIATE_PREFIX, l); 1386 break; 1387 } 1388 /* Fall through. Let output_addr_const deal with it. */ 1389 case CONST_INT: 1390 fprintf(file,"%s",IMMEDIATE_PREFIX); 1391 if (code == 'C' || code == 'X') 1392 { 1393 fprintf (file, "%ld", 1394 (long) (INTVAL (x) / current_frame_info.stld_sz)); 1395 break; 1396 } 1397 /* Fall through */ 1398 default : 1399 output_addr_const (file, x); 1400 break; 1401 } 1402} 1403 1404/* Print a memory address as an operand to reference that memory location. */ 1405 1406static void 1407epiphany_print_operand_address (FILE *file, rtx addr) 1408{ 1409 register rtx base, index = 0; 1410 int offset = 0; 1411 1412 switch (GET_CODE (addr)) 1413 { 1414 case REG : 1415 fputs (reg_names[REGNO (addr)], file); 1416 break; 1417 case SYMBOL_REF : 1418 if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr)) 1419 { 1420 output_addr_const (file, addr); 1421 } 1422 else 1423 { 1424 output_addr_const (file, addr); 1425 } 1426 break; 1427 case PLUS : 1428 if (GET_CODE (XEXP (addr, 0)) == CONST_INT) 1429 offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1); 1430 else if (GET_CODE (XEXP (addr, 1)) == CONST_INT) 1431 offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0); 1432 else 1433 base = XEXP (addr, 0), index = XEXP (addr, 1); 1434 gcc_assert (GET_CODE (base) == REG); 1435 fputs (reg_names[REGNO (base)], file); 1436 if (index == 0) 1437 { 1438 /* 1439 ** ++rk quirky method to scale offset for ld/str....... 1440 */ 1441 fprintf (file, ",%s%d", IMMEDIATE_PREFIX, 1442 offset/current_frame_info.stld_sz); 1443 } 1444 else 1445 { 1446 switch (GET_CODE (index)) 1447 { 1448 case REG: 1449 fprintf (file, ",%s", reg_names[REGNO (index)]); 1450 break; 1451 case SYMBOL_REF: 1452 fputc (',', file), output_addr_const (file, index); 1453 break; 1454 default: 1455 gcc_unreachable (); 1456 } 1457 } 1458 break; 1459 case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: case POST_MODIFY: 1460 /* We shouldn't get here as we've lost the mode of the memory object 1461 (which says how much to inc/dec by. */ 1462 gcc_unreachable (); 1463 break; 1464 default: 1465 output_addr_const (file, addr); 1466 break; 1467 } 1468} 1469 1470void 1471epiphany_final_prescan_insn (rtx_insn *insn ATTRIBUTE_UNUSED, 1472 rtx *opvec ATTRIBUTE_UNUSED, 1473 int noperands ATTRIBUTE_UNUSED) 1474{ 1475 int i = epiphany_n_nops; 1476 rtx pat ATTRIBUTE_UNUSED; 1477 1478 while (i--) 1479 fputs ("\tnop\n", asm_out_file); 1480} 1481 1482 1483/* Worker function for TARGET_RETURN_IN_MEMORY. */ 1484 1485static bool 1486epiphany_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) 1487{ 1488 HOST_WIDE_INT size = int_size_in_bytes (type); 1489 1490 if (AGGREGATE_TYPE_P (type) 1491 && (TYPE_MODE (type) == BLKmode || TYPE_NEEDS_CONSTRUCTING (type))) 1492 return true; 1493 return (size == -1 || size > 8); 1494} 1495 1496/* For EPIPHANY, All aggregates and arguments greater than 8 bytes are 1497 passed by reference. */ 1498 1499static bool 1500epiphany_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED, 1501 machine_mode mode, const_tree type, 1502 bool named ATTRIBUTE_UNUSED) 1503{ 1504 if (type) 1505 { 1506 if (AGGREGATE_TYPE_P (type) 1507 && (mode == BLKmode || TYPE_NEEDS_CONSTRUCTING (type))) 1508 return true; 1509 } 1510 return false; 1511} 1512 1513 1514static rtx 1515epiphany_function_value (const_tree ret_type, 1516 const_tree fn_decl_or_type ATTRIBUTE_UNUSED, 1517 bool outgoing ATTRIBUTE_UNUSED) 1518{ 1519 machine_mode mode; 1520 1521 mode = TYPE_MODE (ret_type); 1522 /* We must change the mode like PROMOTE_MODE does. 1523 ??? PROMOTE_MODE is ignored for non-scalar types. 1524 The set of types tested here has to be kept in sync 1525 with the one in explow.c:promote_mode. */ 1526 if (GET_MODE_CLASS (mode) == MODE_INT 1527 && GET_MODE_SIZE (mode) < 4 1528 && (TREE_CODE (ret_type) == INTEGER_TYPE 1529 || TREE_CODE (ret_type) == ENUMERAL_TYPE 1530 || TREE_CODE (ret_type) == BOOLEAN_TYPE 1531 || TREE_CODE (ret_type) == OFFSET_TYPE)) 1532 mode = SImode; 1533 return gen_rtx_REG (mode, 0); 1534} 1535 1536static rtx 1537epiphany_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) 1538{ 1539 return gen_rtx_REG (mode, 0); 1540} 1541 1542static bool 1543epiphany_function_value_regno_p (const unsigned int regno ATTRIBUTE_UNUSED) 1544{ 1545 return regno == 0; 1546} 1547 1548/* Fix up invalid option settings. */ 1549static void 1550epiphany_override_options (void) 1551{ 1552 if (epiphany_stack_offset < 4) 1553 error ("stack_offset must be at least 4"); 1554 if (epiphany_stack_offset & 3) 1555 error ("stack_offset must be a multiple of 4"); 1556 epiphany_stack_offset = (epiphany_stack_offset + 3) & -4; 1557 if (!TARGET_SOFT_CMPSF) 1558 flag_finite_math_only = 1; 1559 1560 /* This needs to be done at start up. It's convenient to do it here. */ 1561 epiphany_init (); 1562} 1563 1564/* For a DImode load / store SET, make a SImode set for a 1565 REG_FRAME_RELATED_EXPR note, using OFFSET to create a high or lowpart 1566 subreg. */ 1567static rtx 1568frame_subreg_note (rtx set, int offset) 1569{ 1570 rtx src = simplify_gen_subreg (SImode, SET_SRC (set), DImode, offset); 1571 rtx dst = simplify_gen_subreg (SImode, SET_DEST (set), DImode, offset); 1572 1573 set = gen_rtx_SET (VOIDmode, dst ,src); 1574 RTX_FRAME_RELATED_P (set) = 1; 1575 return set; 1576} 1577 1578static rtx_insn * 1579frame_insn (rtx x) 1580{ 1581 int i; 1582 rtx note = NULL_RTX; 1583 rtx_insn *insn; 1584 1585 if (GET_CODE (x) == PARALLEL) 1586 { 1587 rtx part = XVECEXP (x, 0, 0); 1588 1589 if (GET_MODE (SET_DEST (part)) == DImode) 1590 { 1591 note = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (XVECLEN (x, 0) + 1)); 1592 XVECEXP (note, 0, 0) = frame_subreg_note (part, 0); 1593 XVECEXP (note, 0, 1) = frame_subreg_note (part, UNITS_PER_WORD); 1594 for (i = XVECLEN (x, 0) - 1; i >= 1; i--) 1595 { 1596 part = copy_rtx (XVECEXP (x, 0, i)); 1597 1598 if (GET_CODE (part) == SET) 1599 RTX_FRAME_RELATED_P (part) = 1; 1600 XVECEXP (note, 0, i + 1) = part; 1601 } 1602 } 1603 else 1604 { 1605 for (i = XVECLEN (x, 0) - 1; i >= 0; i--) 1606 { 1607 part = XVECEXP (x, 0, i); 1608 1609 if (GET_CODE (part) == SET) 1610 RTX_FRAME_RELATED_P (part) = 1; 1611 } 1612 } 1613 } 1614 else if (GET_CODE (x) == SET && GET_MODE (SET_DEST (x)) == DImode) 1615 note = gen_rtx_PARALLEL (VOIDmode, 1616 gen_rtvec (2, frame_subreg_note (x, 0), 1617 frame_subreg_note (x, UNITS_PER_WORD))); 1618 insn = emit_insn (x); 1619 RTX_FRAME_RELATED_P (insn) = 1; 1620 if (note) 1621 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note); 1622 return insn; 1623} 1624 1625static rtx_insn * 1626frame_move_insn (rtx to, rtx from) 1627{ 1628 return frame_insn (gen_rtx_SET (VOIDmode, to, from)); 1629} 1630 1631/* Generate a MEM referring to a varargs argument slot. */ 1632 1633static rtx 1634gen_varargs_mem (machine_mode mode, rtx addr) 1635{ 1636 rtx mem = gen_rtx_MEM (mode, addr); 1637 MEM_NOTRAP_P (mem) = 1; 1638 set_mem_alias_set (mem, get_varargs_alias_set ()); 1639 return mem; 1640} 1641 1642/* Emit instructions to save or restore registers in the range [MIN..LIMIT) . 1643 If EPILOGUE_P is 0, save; if it is one, restore. 1644 ADDR is the stack slot to save the first register to; subsequent 1645 registers are written to lower addresses. 1646 However, the order of register pairs can be reversed in order to 1647 use double-word load-store instructions. Likewise, an unpaired single 1648 word save slot can be skipped while double saves are carried out, and 1649 reused when a single register is to be saved. */ 1650 1651static void 1652epiphany_emit_save_restore (int min, int limit, rtx addr, int epilogue_p) 1653{ 1654 int i; 1655 int stack_offset 1656 = current_frame_info.first_slot >= 0 ? epiphany_stack_offset : 0; 1657 rtx skipped_mem = NULL_RTX; 1658 int last_saved = limit - 1; 1659 1660 if (!optimize) 1661 while (last_saved >= 0 1662 && !TEST_HARD_REG_BIT (current_frame_info.gmask, last_saved)) 1663 last_saved--; 1664 for (i = 0; i < limit; i++) 1665 { 1666 machine_mode mode = word_mode; 1667 rtx mem, reg; 1668 int n = i; 1669 rtx (*gen_mem) (machine_mode, rtx) = gen_frame_mem; 1670 1671 /* Make sure we push the arguments in the right order. */ 1672 if (n < MAX_EPIPHANY_PARM_REGS && crtl->args.pretend_args_size) 1673 { 1674 n = MAX_EPIPHANY_PARM_REGS - 1 - n; 1675 gen_mem = gen_varargs_mem; 1676 } 1677 if (stack_offset == current_frame_info.first_slot_size 1678 && current_frame_info.first_slot >= 0) 1679 { 1680 if (current_frame_info.first_slot_size > UNITS_PER_WORD) 1681 { 1682 mode = DImode; 1683 addr = plus_constant (Pmode, addr, 1684 - (HOST_WIDE_INT) UNITS_PER_WORD); 1685 } 1686 if (i-- < min || !epilogue_p) 1687 goto next_slot; 1688 n = current_frame_info.first_slot; 1689 gen_mem = gen_frame_mem; 1690 } 1691 else if (n == UNKNOWN_REGNUM 1692 && stack_offset > current_frame_info.first_slot_size) 1693 { 1694 i--; 1695 goto next_slot; 1696 } 1697 else if (!TEST_HARD_REG_BIT (current_frame_info.gmask, n)) 1698 continue; 1699 else if (i < min) 1700 goto next_slot; 1701 1702 /* Check for a register pair to save. */ 1703 if (n == i 1704 && (n >= MAX_EPIPHANY_PARM_REGS || crtl->args.pretend_args_size == 0) 1705 && (n & 1) == 0 && n+1 < limit 1706 && TEST_HARD_REG_BIT (current_frame_info.gmask, n+1)) 1707 { 1708 /* If it fits in the current stack slot pair, place it there. */ 1709 if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 0 1710 && stack_offset != 2 * UNITS_PER_WORD 1711 && (current_frame_info.last_slot < 0 1712 || INTVAL (XEXP (addr, 1)) != UNITS_PER_WORD) 1713 && (n+1 != last_saved || !skipped_mem)) 1714 { 1715 mode = DImode; 1716 i++; 1717 addr = plus_constant (Pmode, addr, 1718 - (HOST_WIDE_INT) UNITS_PER_WORD); 1719 } 1720 /* If it fits in the following stack slot pair, that's fine, too. */ 1721 else if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 4 1722 && stack_offset != 2 * UNITS_PER_WORD 1723 && stack_offset != 3 * UNITS_PER_WORD 1724 && (current_frame_info.last_slot < 0 1725 || INTVAL (XEXP (addr, 1)) != 2 * UNITS_PER_WORD) 1726 && n + 1 != last_saved) 1727 { 1728 gcc_assert (!skipped_mem); 1729 stack_offset -= GET_MODE_SIZE (mode); 1730 skipped_mem = gen_mem (mode, addr); 1731 mode = DImode; 1732 i++; 1733 addr = plus_constant (Pmode, addr, 1734 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD); 1735 } 1736 } 1737 reg = gen_rtx_REG (mode, n); 1738 if (mode != DImode && skipped_mem) 1739 mem = skipped_mem; 1740 else 1741 mem = gen_mem (mode, addr); 1742 1743 /* If we are loading / storing LR, note the offset that 1744 gen_reload_insi_ra requires. Since GPR_LR is even, 1745 we only need to test n, even if mode is DImode. */ 1746 gcc_assert ((GPR_LR & 1) == 0); 1747 if (n == GPR_LR) 1748 { 1749 long lr_slot_offset = 0; 1750 rtx m_addr = XEXP (mem, 0); 1751 1752 if (GET_CODE (m_addr) == PLUS) 1753 lr_slot_offset = INTVAL (XEXP (m_addr, 1)); 1754 if (frame_pointer_needed) 1755 lr_slot_offset += (current_frame_info.first_slot_offset 1756 - current_frame_info.total_size); 1757 if (MACHINE_FUNCTION (cfun)->lr_slot_known) 1758 gcc_assert (MACHINE_FUNCTION (cfun)->lr_slot_offset 1759 == lr_slot_offset); 1760 MACHINE_FUNCTION (cfun)->lr_slot_offset = lr_slot_offset; 1761 MACHINE_FUNCTION (cfun)->lr_slot_known = 1; 1762 } 1763 1764 if (!epilogue_p) 1765 frame_move_insn (mem, reg); 1766 else if (n >= MAX_EPIPHANY_PARM_REGS || !crtl->args.pretend_args_size) 1767 emit_move_insn (reg, mem); 1768 if (mem == skipped_mem) 1769 { 1770 skipped_mem = NULL_RTX; 1771 continue; 1772 } 1773 next_slot: 1774 addr = plus_constant (Pmode, addr, -(HOST_WIDE_INT) UNITS_PER_WORD); 1775 stack_offset -= GET_MODE_SIZE (mode); 1776 } 1777} 1778 1779void 1780epiphany_expand_prologue (void) 1781{ 1782 int interrupt_p; 1783 enum epiphany_function_type fn_type; 1784 rtx addr, mem, off, reg; 1785 1786 if (!current_frame_info.initialized) 1787 epiphany_compute_frame_size (get_frame_size ()); 1788 1789 /* It is debatable if we should adjust this by epiphany_stack_offset. */ 1790 if (flag_stack_usage_info) 1791 current_function_static_stack_size = current_frame_info.total_size; 1792 1793 fn_type = epiphany_compute_function_type (current_function_decl); 1794 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type); 1795 1796 if (interrupt_p) 1797 { 1798 addr = plus_constant (Pmode, stack_pointer_rtx, 1799 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD); 1800 if (!lookup_attribute ("forwarder_section", 1801 DECL_ATTRIBUTES (current_function_decl)) 1802 || !epiphany_is_long_call_p (XEXP (DECL_RTL (current_function_decl), 1803 0))) 1804 frame_move_insn (gen_frame_mem (DImode, addr), 1805 gen_rtx_REG (DImode, GPR_0)); 1806 frame_move_insn (gen_rtx_REG (SImode, GPR_0), 1807 gen_rtx_REG (word_mode, STATUS_REGNUM)); 1808 frame_move_insn (gen_rtx_REG (SImode, GPR_1), 1809 gen_rtx_REG (word_mode, IRET_REGNUM)); 1810 mem = gen_frame_mem (BLKmode, stack_pointer_rtx); 1811 off = GEN_INT (-current_frame_info.first_slot_offset); 1812 frame_insn (gen_stack_adjust_add (off, mem)); 1813 if (!epiphany_uninterruptible_p (current_function_decl)) 1814 emit_insn (gen_gie ()); 1815 addr = plus_constant (Pmode, stack_pointer_rtx, 1816 current_frame_info.first_slot_offset 1817 - (HOST_WIDE_INT) 3 * UNITS_PER_WORD); 1818 } 1819 else 1820 { 1821 addr = plus_constant (Pmode, stack_pointer_rtx, 1822 epiphany_stack_offset 1823 - (HOST_WIDE_INT) UNITS_PER_WORD); 1824 epiphany_emit_save_restore (0, current_frame_info.small_threshold, 1825 addr, 0); 1826 /* Allocate register save area; for small to medium size frames, 1827 allocate the entire frame; this is joint with one register save. */ 1828 if (current_frame_info.first_slot >= 0) 1829 { 1830 machine_mode mode 1831 = (current_frame_info.first_slot_size == UNITS_PER_WORD 1832 ? word_mode : DImode); 1833 1834 off = GEN_INT (-current_frame_info.first_slot_offset); 1835 mem = gen_frame_mem (BLKmode, 1836 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off)); 1837 frame_insn (gen_stack_adjust_str 1838 (gen_frame_mem (mode, stack_pointer_rtx), 1839 gen_rtx_REG (mode, current_frame_info.first_slot), 1840 off, mem)); 1841 addr = plus_constant (Pmode, addr, 1842 current_frame_info.first_slot_offset); 1843 } 1844 } 1845 epiphany_emit_save_restore (current_frame_info.small_threshold, 1846 FIRST_PSEUDO_REGISTER, addr, 0); 1847 if (current_frame_info.need_fp) 1848 frame_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); 1849 /* For large frames, allocate bulk of frame. This is usually joint with one 1850 register save. */ 1851 if (current_frame_info.last_slot >= 0) 1852 { 1853 rtx ip, mem2, note; 1854 rtx_insn *insn; 1855 1856 gcc_assert (current_frame_info.last_slot != GPR_FP 1857 || (!current_frame_info.need_fp 1858 && current_frame_info.first_slot < 0)); 1859 off = GEN_INT (-current_frame_info.last_slot_offset); 1860 mem = gen_frame_mem (BLKmode, 1861 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off)); 1862 ip = gen_rtx_REG (Pmode, GPR_IP); 1863 frame_move_insn (ip, off); 1864 reg = gen_rtx_REG (word_mode, current_frame_info.last_slot), 1865 mem2 = gen_frame_mem (word_mode, stack_pointer_rtx), 1866 insn = frame_insn (gen_stack_adjust_str (mem2, reg, ip, mem)); 1867 /* Instruction scheduling can separate the instruction setting IP from 1868 INSN so that dwarf2out_frame_debug_expr becomes confused what the 1869 temporary register is. Example: _gcov.o */ 1870 note = gen_rtx_SET (VOIDmode, stack_pointer_rtx, 1871 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off)); 1872 note = gen_rtx_PARALLEL (VOIDmode, 1873 gen_rtvec (2, gen_rtx_SET (VOIDmode, mem2, reg), 1874 note)); 1875 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note); 1876 } 1877 /* If there is only one or no register to save, yet we have a large frame, 1878 use an add. */ 1879 else if (current_frame_info.last_slot_offset) 1880 { 1881 mem = gen_frame_mem (BLKmode, 1882 plus_constant (Pmode, stack_pointer_rtx, 1883 current_frame_info.last_slot_offset)); 1884 off = GEN_INT (-current_frame_info.last_slot_offset); 1885 if (!SIMM11 (INTVAL (off))) 1886 { 1887 reg = gen_rtx_REG (Pmode, GPR_IP); 1888 frame_move_insn (reg, off); 1889 off = reg; 1890 } 1891 frame_insn (gen_stack_adjust_add (off, mem)); 1892 } 1893} 1894 1895void 1896epiphany_expand_epilogue (int sibcall_p) 1897{ 1898 int interrupt_p; 1899 enum epiphany_function_type fn_type; 1900 rtx mem, addr, reg, off; 1901 HOST_WIDE_INT restore_offset; 1902 1903 fn_type = epiphany_compute_function_type( current_function_decl); 1904 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type); 1905 1906 /* For variable frames, deallocate bulk of frame. */ 1907 if (current_frame_info.need_fp) 1908 { 1909 mem = gen_frame_mem (BLKmode, stack_pointer_rtx); 1910 emit_insn (gen_stack_adjust_mov (mem)); 1911 } 1912 /* Else for large static frames, deallocate bulk of frame. */ 1913 else if (current_frame_info.last_slot_offset) 1914 { 1915 mem = gen_frame_mem (BLKmode, stack_pointer_rtx); 1916 reg = gen_rtx_REG (Pmode, GPR_IP); 1917 emit_move_insn (reg, GEN_INT (current_frame_info.last_slot_offset)); 1918 emit_insn (gen_stack_adjust_add (reg, mem)); 1919 } 1920 restore_offset = (interrupt_p 1921 ? - 3 * UNITS_PER_WORD 1922 : epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD); 1923 addr = plus_constant (Pmode, stack_pointer_rtx, 1924 (current_frame_info.first_slot_offset 1925 + restore_offset)); 1926 epiphany_emit_save_restore (current_frame_info.small_threshold, 1927 FIRST_PSEUDO_REGISTER, addr, 1); 1928 1929 if (interrupt_p && !epiphany_uninterruptible_p (current_function_decl)) 1930 emit_insn (gen_gid ()); 1931 1932 off = GEN_INT (current_frame_info.first_slot_offset); 1933 mem = gen_frame_mem (BLKmode, stack_pointer_rtx); 1934 /* For large / variable size frames, deallocating the register save area is 1935 joint with one register restore; for medium size frames, we use a 1936 dummy post-increment load to dealloacte the whole frame. */ 1937 if (!SIMM11 (INTVAL (off)) || current_frame_info.last_slot >= 0) 1938 { 1939 emit_insn (gen_stack_adjust_ldr 1940 (gen_rtx_REG (word_mode, 1941 (current_frame_info.last_slot >= 0 1942 ? current_frame_info.last_slot : GPR_IP)), 1943 gen_frame_mem (word_mode, stack_pointer_rtx), 1944 off, 1945 mem)); 1946 } 1947 /* While for small frames, we deallocate the entire frame with one add. */ 1948 else if (INTVAL (off)) 1949 { 1950 emit_insn (gen_stack_adjust_add (off, mem)); 1951 } 1952 if (interrupt_p) 1953 { 1954 emit_move_insn (gen_rtx_REG (word_mode, STATUS_REGNUM), 1955 gen_rtx_REG (SImode, GPR_0)); 1956 emit_move_insn (gen_rtx_REG (word_mode, IRET_REGNUM), 1957 gen_rtx_REG (SImode, GPR_1)); 1958 addr = plus_constant (Pmode, stack_pointer_rtx, 1959 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD); 1960 emit_move_insn (gen_rtx_REG (DImode, GPR_0), 1961 gen_frame_mem (DImode, addr)); 1962 } 1963 addr = plus_constant (Pmode, stack_pointer_rtx, 1964 epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD); 1965 epiphany_emit_save_restore (0, current_frame_info.small_threshold, addr, 1); 1966 if (!sibcall_p) 1967 { 1968 if (interrupt_p) 1969 emit_jump_insn (gen_return_internal_interrupt()); 1970 else 1971 emit_jump_insn (gen_return_i ()); 1972 } 1973} 1974 1975int 1976epiphany_initial_elimination_offset (int from, int to) 1977{ 1978 epiphany_compute_frame_size (get_frame_size ()); 1979 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) 1980 return current_frame_info.total_size - current_frame_info.reg_size; 1981 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) 1982 return current_frame_info.first_slot_offset - current_frame_info.reg_size; 1983 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) 1984 return (current_frame_info.total_size 1985 - ((current_frame_info.pretend_size + 4) & -8)); 1986 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) 1987 return (current_frame_info.first_slot_offset 1988 - ((current_frame_info.pretend_size + 4) & -8)); 1989 gcc_unreachable (); 1990} 1991 1992bool 1993epiphany_regno_rename_ok (unsigned, unsigned dst) 1994{ 1995 enum epiphany_function_type fn_type; 1996 1997 fn_type = epiphany_compute_function_type (current_function_decl); 1998 if (!EPIPHANY_INTERRUPT_P (fn_type)) 1999 return true; 2000 if (df_regs_ever_live_p (dst)) 2001 return true; 2002 return false; 2003} 2004 2005static int 2006epiphany_issue_rate (void) 2007{ 2008 return 2; 2009} 2010 2011/* Function to update the integer COST 2012 based on the relationship between INSN that is dependent on 2013 DEP_INSN through the dependence LINK. The default is to make no 2014 adjustment to COST. This can be used for example to specify to 2015 the scheduler that an output- or anti-dependence does not incur 2016 the same cost as a data-dependence. The return value should be 2017 the new value for COST. */ 2018static int 2019epiphany_adjust_cost (rtx_insn *insn, rtx link, rtx_insn *dep_insn, int cost) 2020{ 2021 if (REG_NOTE_KIND (link) == 0) 2022 { 2023 rtx dep_set; 2024 2025 if (recog_memoized (insn) < 0 2026 || recog_memoized (dep_insn) < 0) 2027 return cost; 2028 2029 dep_set = single_set (dep_insn); 2030 2031 /* The latency that we specify in the scheduling description refers 2032 to the actual output, not to an auto-increment register; for that, 2033 the latency is one. */ 2034 if (dep_set && MEM_P (SET_SRC (dep_set)) && cost > 1) 2035 { 2036 rtx set = single_set (insn); 2037 2038 if (set 2039 && !reg_overlap_mentioned_p (SET_DEST (dep_set), SET_SRC (set)) 2040 && (!MEM_P (SET_DEST (set)) 2041 || !reg_overlap_mentioned_p (SET_DEST (dep_set), 2042 XEXP (SET_DEST (set), 0)))) 2043 cost = 1; 2044 } 2045 } 2046 return cost; 2047} 2048 2049#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X) 2050 2051#define RTX_OK_FOR_BASE_P(X) \ 2052 (REG_P (X) && REG_OK_FOR_BASE_P (X)) 2053 2054#define RTX_OK_FOR_INDEX_P(MODE, X) \ 2055 ((GET_MODE_CLASS (MODE) != MODE_VECTOR_INT \ 2056 || epiphany_vect_align >= GET_MODE_SIZE (MODE)) \ 2057 && (REG_P (X) && REG_OK_FOR_INDEX_P (X))) 2058 2059#define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \ 2060(GET_CODE (X) == PLUS \ 2061 && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \ 2062 && (RTX_OK_FOR_INDEX_P (MODE, XEXP (X, 1)) \ 2063 || RTX_OK_FOR_OFFSET_P (MODE, XEXP (X, 1)))) 2064 2065static bool 2066epiphany_legitimate_address_p (machine_mode mode, rtx x, bool strict) 2067{ 2068#define REG_OK_FOR_BASE_P(X) \ 2069 (strict ? GPR_P (REGNO (X)) : GPR_AP_OR_PSEUDO_P (REGNO (X))) 2070 if (RTX_OK_FOR_BASE_P (x)) 2071 return true; 2072 if (RTX_FRAME_OFFSET_P (x)) 2073 return true; 2074 if (LEGITIMATE_OFFSET_ADDRESS_P (mode, x)) 2075 return true; 2076 /* If this is a misaligned stack access, don't force it to reg+index. */ 2077 if (GET_MODE_SIZE (mode) == 8 2078 && GET_CODE (x) == PLUS && XEXP (x, 0) == stack_pointer_rtx 2079 /* Decomposed to SImode; GET_MODE_SIZE (SImode) == 4 */ 2080 && !(INTVAL (XEXP (x, 1)) & 3) 2081 && INTVAL (XEXP (x, 1)) >= -2047 * 4 2082 && INTVAL (XEXP (x, 1)) <= 2046 * 4) 2083 return true; 2084 if (TARGET_POST_INC 2085 && (GET_CODE (x) == POST_DEC || GET_CODE (x) == POST_INC) 2086 && RTX_OK_FOR_BASE_P (XEXP ((x), 0))) 2087 return true; 2088 if ((TARGET_POST_MODIFY || reload_completed) 2089 && GET_CODE (x) == POST_MODIFY 2090 && GET_CODE (XEXP ((x), 1)) == PLUS 2091 && rtx_equal_p (XEXP ((x), 0), XEXP (XEXP ((x), 1), 0)) 2092 && LEGITIMATE_OFFSET_ADDRESS_P (mode, XEXP ((x), 1))) 2093 return true; 2094 if (mode == BLKmode) 2095 return epiphany_legitimate_address_p (SImode, x, strict); 2096 return false; 2097} 2098 2099static reg_class_t 2100epiphany_secondary_reload (bool in_p, rtx x, reg_class_t rclass, 2101 machine_mode mode ATTRIBUTE_UNUSED, 2102 secondary_reload_info *sri) 2103{ 2104 /* This could give more reload inheritance, but we are missing some 2105 reload infrastructure. */ 2106 if (0) 2107 if (in_p && GET_CODE (x) == UNSPEC 2108 && satisfies_constraint_Sra (x) && !satisfies_constraint_Rra (x)) 2109 { 2110 gcc_assert (rclass == GENERAL_REGS); 2111 sri->icode = CODE_FOR_reload_insi_ra; 2112 return NO_REGS; 2113 } 2114 return NO_REGS; 2115} 2116 2117bool 2118epiphany_is_long_call_p (rtx x) 2119{ 2120 tree decl = SYMBOL_REF_DECL (x); 2121 bool ret_val = !TARGET_SHORT_CALLS; 2122 tree attrs; 2123 2124 /* ??? Is it safe to default to ret_val if decl is NULL? We should 2125 probably encode information via encode_section_info, and also 2126 have (an) option(s) to take SYMBOL_FLAG_LOCAL and/or SYMBOL_FLAG_EXTERNAL 2127 into account. */ 2128 if (decl) 2129 { 2130 attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl)); 2131 if (lookup_attribute ("long_call", attrs)) 2132 ret_val = true; 2133 else if (lookup_attribute ("short_call", attrs)) 2134 ret_val = false; 2135 } 2136 return ret_val; 2137} 2138 2139bool 2140epiphany_small16 (rtx x) 2141{ 2142 rtx base = x; 2143 rtx offs ATTRIBUTE_UNUSED = const0_rtx; 2144 2145 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS) 2146 { 2147 base = XEXP (XEXP (x, 0), 0); 2148 offs = XEXP (XEXP (x, 0), 1); 2149 } 2150 if (GET_CODE (base) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (base) 2151 && epiphany_is_long_call_p (base)) 2152 return false; 2153 return TARGET_SMALL16 != 0; 2154} 2155 2156/* Return nonzero if it is ok to make a tail-call to DECL. */ 2157static bool 2158epiphany_function_ok_for_sibcall (tree decl, tree exp) 2159{ 2160 bool cfun_interrupt_p, call_interrupt_p; 2161 2162 cfun_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type 2163 (current_function_decl)); 2164 if (decl) 2165 call_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type (decl)); 2166 else 2167 { 2168 tree fn_type = TREE_TYPE (CALL_EXPR_FN (exp)); 2169 2170 gcc_assert (POINTER_TYPE_P (fn_type)); 2171 fn_type = TREE_TYPE (fn_type); 2172 gcc_assert (TREE_CODE (fn_type) == FUNCTION_TYPE 2173 || TREE_CODE (fn_type) == METHOD_TYPE); 2174 call_interrupt_p 2175 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (fn_type)) != NULL; 2176 } 2177 2178 /* Don't tailcall from or to an ISR routine - although we could in 2179 principle tailcall from one ISR routine to another, we'd need to 2180 handle this in sibcall_epilogue to make it work. */ 2181 if (cfun_interrupt_p || call_interrupt_p) 2182 return false; 2183 2184 /* Everything else is ok. */ 2185 return true; 2186} 2187 2188/* T is a function declaration or the MEM_EXPR of a MEM passed to a call 2189 expander. 2190 Return true iff the type of T has the uninterruptible attribute. 2191 If T is NULL, return false. */ 2192bool 2193epiphany_uninterruptible_p (tree t) 2194{ 2195 tree attrs; 2196 2197 if (t) 2198 { 2199 attrs = TYPE_ATTRIBUTES (TREE_TYPE (t)); 2200 if (lookup_attribute ("disinterrupt", attrs)) 2201 return true; 2202 } 2203 return false; 2204} 2205 2206bool 2207epiphany_call_uninterruptible_p (rtx mem) 2208{ 2209 rtx addr = XEXP (mem, 0); 2210 tree t = NULL_TREE; 2211 2212 if (GET_CODE (addr) == SYMBOL_REF) 2213 t = SYMBOL_REF_DECL (addr); 2214 if (!t) 2215 t = MEM_EXPR (mem); 2216 return epiphany_uninterruptible_p (t); 2217} 2218 2219static machine_mode 2220epiphany_promote_function_mode (const_tree type, machine_mode mode, 2221 int *punsignedp ATTRIBUTE_UNUSED, 2222 const_tree funtype ATTRIBUTE_UNUSED, 2223 int for_return ATTRIBUTE_UNUSED) 2224{ 2225 int dummy; 2226 2227 return promote_mode (type, mode, &dummy); 2228} 2229 2230static void 2231epiphany_conditional_register_usage (void) 2232{ 2233 int i; 2234 2235 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM) 2236 { 2237 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; 2238 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; 2239 } 2240 if (TARGET_HALF_REG_FILE) 2241 { 2242 for (i = 32; i <= 63; i++) 2243 { 2244 fixed_regs[i] = 1; 2245 call_used_regs[i] = 1; 2246 } 2247 } 2248 if (epiphany_m1reg >= 0) 2249 { 2250 fixed_regs[epiphany_m1reg] = 1; 2251 call_used_regs[epiphany_m1reg] = 1; 2252 } 2253 if (!TARGET_PREFER_SHORT_INSN_REGS) 2254 CLEAR_HARD_REG_SET (reg_class_contents[SHORT_INSN_REGS]); 2255 COPY_HARD_REG_SET (reg_class_contents[SIBCALL_REGS], 2256 reg_class_contents[GENERAL_REGS]); 2257 /* It would be simpler and quicker if we could just use 2258 AND_COMPL_HARD_REG_SET, alas, call_used_reg_set is yet uninitialized; 2259 it is set up later by our caller. */ 2260 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 2261 if (!call_used_regs[i]) 2262 CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], i); 2263} 2264 2265/* Determine where to put an argument to a function. 2266 Value is zero to push the argument on the stack, 2267 or a hard register in which to store the argument. 2268 2269 MODE is the argument's machine mode. 2270 TYPE is the data type of the argument (as a tree). 2271 This is null for libcalls where that information may 2272 not be available. 2273 CUM is a variable of type CUMULATIVE_ARGS which gives info about 2274 the preceding args and about the function being called. 2275 NAMED is nonzero if this argument is a named parameter 2276 (otherwise it is an extra parameter matching an ellipsis). */ 2277/* On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in 2278 registers and the rest are pushed. */ 2279static rtx 2280epiphany_function_arg (cumulative_args_t cum_v, machine_mode mode, 2281 const_tree type, bool named ATTRIBUTE_UNUSED) 2282{ 2283 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v); 2284 2285 if (PASS_IN_REG_P (cum, mode, type)) 2286 return gen_rtx_REG (mode, ROUND_ADVANCE_CUM (cum, mode, type)); 2287 return 0; 2288} 2289 2290/* Update the data in CUM to advance over an argument 2291 of mode MODE and data type TYPE. 2292 (TYPE is null for libcalls where that information may not be available.) */ 2293static void 2294epiphany_function_arg_advance (cumulative_args_t cum_v, machine_mode mode, 2295 const_tree type, bool named ATTRIBUTE_UNUSED) 2296{ 2297 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); 2298 2299 *cum = ROUND_ADVANCE_CUM (*cum, mode, type) + ROUND_ADVANCE_ARG (mode, type); 2300} 2301 2302/* Nested function support. 2303 An epiphany trampoline looks like this: 2304 mov r16,%low(fnaddr) 2305 movt r16,%high(fnaddr) 2306 mov ip,%low(cxt) 2307 movt ip,%high(cxt) 2308 jr r16 */ 2309 2310#define EPIPHANY_LOW_RTX(X) \ 2311 (gen_rtx_IOR (SImode, \ 2312 gen_rtx_ASHIFT (SImode, \ 2313 gen_rtx_AND (SImode, (X), GEN_INT (0xff)), GEN_INT (5)), \ 2314 gen_rtx_ASHIFT (SImode, \ 2315 gen_rtx_AND (SImode, (X), GEN_INT (0xff00)), GEN_INT (12)))) 2316#define EPIPHANY_HIGH_RTX(X) \ 2317 EPIPHANY_LOW_RTX (gen_rtx_LSHIFTRT (SImode, (X), GEN_INT (16))) 2318 2319/* Emit RTL insns to initialize the variable parts of a trampoline. 2320 FNADDR is an RTX for the address of the function's pure code. 2321 CXT is an RTX for the static chain value for the function. */ 2322static void 2323epiphany_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt) 2324{ 2325 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); 2326 rtx tramp = force_reg (Pmode, XEXP (tramp_mem, 0)); 2327 2328 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 0)), 2329 gen_rtx_IOR (SImode, GEN_INT (0x4002000b), 2330 EPIPHANY_LOW_RTX (fnaddr))); 2331 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 4)), 2332 gen_rtx_IOR (SImode, GEN_INT (0x5002000b), 2333 EPIPHANY_HIGH_RTX (fnaddr))); 2334 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 8)), 2335 gen_rtx_IOR (SImode, GEN_INT (0x2002800b), 2336 EPIPHANY_LOW_RTX (cxt))); 2337 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 12)), 2338 gen_rtx_IOR (SImode, GEN_INT (0x3002800b), 2339 EPIPHANY_HIGH_RTX (cxt))); 2340 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 16)), 2341 GEN_INT (0x0802014f)); 2342} 2343 2344bool 2345epiphany_optimize_mode_switching (int entity) 2346{ 2347 if (MACHINE_FUNCTION (cfun)->sw_entities_processed & (1 << entity)) 2348 return false; 2349 switch (entity) 2350 { 2351 case EPIPHANY_MSW_ENTITY_AND: 2352 case EPIPHANY_MSW_ENTITY_OR: 2353 case EPIPHANY_MSW_ENTITY_CONFIG: 2354 return true; 2355 case EPIPHANY_MSW_ENTITY_NEAREST: 2356 case EPIPHANY_MSW_ENTITY_TRUNC: 2357 return optimize > 0; 2358 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN: 2359 return MACHINE_FUNCTION (cfun)->unknown_mode_uses != 0; 2360 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN: 2361 return (MACHINE_FUNCTION (cfun)->sw_entities_processed 2362 & (1 << EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN)) != 0; 2363 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS: 2364 return optimize == 0 || current_pass == pass_mode_switch_use; 2365 } 2366 gcc_unreachable (); 2367} 2368 2369static int 2370epiphany_mode_priority (int entity, int priority) 2371{ 2372 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR 2373 || entity== EPIPHANY_MSW_ENTITY_CONFIG) 2374 return priority; 2375 if (priority > 3) 2376 switch (priority) 2377 { 2378 case 4: return FP_MODE_ROUND_UNKNOWN; 2379 case 5: return FP_MODE_NONE; 2380 default: gcc_unreachable (); 2381 } 2382 switch ((enum attr_fp_mode) epiphany_normal_fp_mode) 2383 { 2384 case FP_MODE_INT: 2385 switch (priority) 2386 { 2387 case 0: return FP_MODE_INT; 2388 case 1: return epiphany_normal_fp_rounding; 2389 case 2: return (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST 2390 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST); 2391 case 3: return FP_MODE_CALLER; 2392 } 2393 case FP_MODE_ROUND_NEAREST: 2394 case FP_MODE_CALLER: 2395 switch (priority) 2396 { 2397 case 0: return FP_MODE_ROUND_NEAREST; 2398 case 1: return FP_MODE_ROUND_TRUNC; 2399 case 2: return FP_MODE_INT; 2400 case 3: return FP_MODE_CALLER; 2401 } 2402 case FP_MODE_ROUND_TRUNC: 2403 switch (priority) 2404 { 2405 case 0: return FP_MODE_ROUND_TRUNC; 2406 case 1: return FP_MODE_ROUND_NEAREST; 2407 case 2: return FP_MODE_INT; 2408 case 3: return FP_MODE_CALLER; 2409 } 2410 case FP_MODE_ROUND_UNKNOWN: 2411 case FP_MODE_NONE: 2412 gcc_unreachable (); 2413 } 2414 gcc_unreachable (); 2415} 2416 2417int 2418epiphany_mode_needed (int entity, rtx_insn *insn) 2419{ 2420 enum attr_fp_mode mode; 2421 2422 if (recog_memoized (insn) < 0) 2423 { 2424 if (entity == EPIPHANY_MSW_ENTITY_AND 2425 || entity == EPIPHANY_MSW_ENTITY_OR 2426 || entity == EPIPHANY_MSW_ENTITY_CONFIG) 2427 return 2; 2428 return FP_MODE_NONE; 2429 } 2430 mode = get_attr_fp_mode (insn); 2431 2432 switch (entity) 2433 { 2434 case EPIPHANY_MSW_ENTITY_AND: 2435 return mode != FP_MODE_NONE && mode != FP_MODE_INT ? 1 : 2; 2436 case EPIPHANY_MSW_ENTITY_OR: 2437 return mode == FP_MODE_INT ? 1 : 2; 2438 case EPIPHANY_MSW_ENTITY_CONFIG: 2439 /* We must know/save config before we set it to something else. 2440 Where we need the original value, we are fine with having it 2441 just unchanged from the function start. 2442 Because of the nature of the mode switching optimization, 2443 a restore will be dominated by a clobber. */ 2444 if (mode != FP_MODE_NONE && mode != FP_MODE_CALLER) 2445 return 1; 2446 /* A cpecial case are abnormal edges, which are deemed to clobber 2447 the mode as well. We need to pin this effect on a actually 2448 dominating insn, and one where the frame can be accessed, too, in 2449 case the pseudo used to save CONFIG doesn't get a hard register. */ 2450 if (CALL_P (insn) && find_reg_note (insn, REG_EH_REGION, NULL_RTX)) 2451 return 1; 2452 return 2; 2453 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN: 2454 if (recog_memoized (insn) == CODE_FOR_set_fp_mode) 2455 mode = (enum attr_fp_mode) epiphany_mode_after (entity, mode, insn); 2456 /* Fall through. */ 2457 case EPIPHANY_MSW_ENTITY_NEAREST: 2458 case EPIPHANY_MSW_ENTITY_TRUNC: 2459 if (mode == FP_MODE_ROUND_UNKNOWN) 2460 { 2461 MACHINE_FUNCTION (cfun)->unknown_mode_uses++; 2462 return FP_MODE_NONE; 2463 } 2464 return mode; 2465 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN: 2466 if (mode == FP_MODE_ROUND_NEAREST || mode == FP_MODE_ROUND_TRUNC) 2467 return FP_MODE_ROUND_UNKNOWN; 2468 return mode; 2469 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS: 2470 if (mode == FP_MODE_ROUND_UNKNOWN) 2471 return epiphany_normal_fp_rounding; 2472 return mode; 2473 default: 2474 gcc_unreachable (); 2475 } 2476} 2477 2478static int 2479epiphany_mode_entry_exit (int entity, bool exit) 2480{ 2481 int normal_mode = epiphany_normal_fp_mode ; 2482 2483 MACHINE_FUNCTION (cfun)->sw_entities_processed |= (1 << entity); 2484 if (epiphany_is_interrupt_p (current_function_decl)) 2485 normal_mode = FP_MODE_CALLER; 2486 switch (entity) 2487 { 2488 case EPIPHANY_MSW_ENTITY_AND: 2489 if (exit) 2490 return normal_mode != FP_MODE_INT ? 1 : 2; 2491 return 0; 2492 case EPIPHANY_MSW_ENTITY_OR: 2493 if (exit) 2494 return normal_mode == FP_MODE_INT ? 1 : 2; 2495 return 0; 2496 case EPIPHANY_MSW_ENTITY_CONFIG: 2497 if (exit) 2498 return 2; 2499 return normal_mode == FP_MODE_CALLER ? 0 : 1; 2500 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN: 2501 if (normal_mode == FP_MODE_ROUND_NEAREST 2502 || normal_mode == FP_MODE_ROUND_TRUNC) 2503 return FP_MODE_ROUND_UNKNOWN; 2504 /* Fall through. */ 2505 case EPIPHANY_MSW_ENTITY_NEAREST: 2506 case EPIPHANY_MSW_ENTITY_TRUNC: 2507 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN: 2508 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS: 2509 return normal_mode; 2510 default: 2511 gcc_unreachable (); 2512 } 2513} 2514 2515int 2516epiphany_mode_after (int entity, int last_mode, rtx_insn *insn) 2517{ 2518 /* We have too few call-saved registers to hope to keep the masks across 2519 calls. */ 2520 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR) 2521 { 2522 if (CALL_P (insn)) 2523 return 0; 2524 return last_mode; 2525 } 2526 /* If there is an abnormal edge, we don't want the config register to 2527 be 'saved' again at the destination. 2528 The frame pointer adjustment is inside a PARALLEL because of the 2529 flags clobber. */ 2530 if (entity == EPIPHANY_MSW_ENTITY_CONFIG && NONJUMP_INSN_P (insn) 2531 && GET_CODE (PATTERN (insn)) == PARALLEL 2532 && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET 2533 && SET_DEST (XVECEXP (PATTERN (insn), 0, 0)) == frame_pointer_rtx) 2534 { 2535 gcc_assert (cfun->has_nonlocal_label); 2536 return 1; 2537 } 2538 if (recog_memoized (insn) < 0) 2539 return last_mode; 2540 if (get_attr_fp_mode (insn) == FP_MODE_ROUND_UNKNOWN 2541 && last_mode != FP_MODE_ROUND_NEAREST && last_mode != FP_MODE_ROUND_TRUNC) 2542 { 2543 if (entity == EPIPHANY_MSW_ENTITY_NEAREST) 2544 return FP_MODE_ROUND_NEAREST; 2545 if (entity == EPIPHANY_MSW_ENTITY_TRUNC) 2546 return FP_MODE_ROUND_TRUNC; 2547 } 2548 if (recog_memoized (insn) == CODE_FOR_set_fp_mode) 2549 { 2550 rtx src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); 2551 int fp_mode; 2552 2553 if (REG_P (src)) 2554 return FP_MODE_CALLER; 2555 fp_mode = INTVAL (XVECEXP (XEXP (src, 0), 0, 0)); 2556 if (entity == EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN 2557 && (fp_mode == FP_MODE_ROUND_NEAREST 2558 || fp_mode == EPIPHANY_MSW_ENTITY_TRUNC)) 2559 return FP_MODE_ROUND_UNKNOWN; 2560 return fp_mode; 2561 } 2562 return last_mode; 2563} 2564 2565static int 2566epiphany_mode_entry (int entity) 2567{ 2568 return epiphany_mode_entry_exit (entity, false); 2569} 2570 2571static int 2572epiphany_mode_exit (int entity) 2573{ 2574 return epiphany_mode_entry_exit (entity, true); 2575} 2576 2577void 2578emit_set_fp_mode (int entity, int mode, int prev_mode ATTRIBUTE_UNUSED, 2579 HARD_REG_SET regs_live ATTRIBUTE_UNUSED) 2580{ 2581 rtx save_cc, cc_reg, mask, src, src2; 2582 enum attr_fp_mode fp_mode; 2583 2584 if (!MACHINE_FUNCTION (cfun)->and_mask) 2585 { 2586 MACHINE_FUNCTION (cfun)->and_mask = gen_reg_rtx (SImode); 2587 MACHINE_FUNCTION (cfun)->or_mask = gen_reg_rtx (SImode); 2588 } 2589 if (entity == EPIPHANY_MSW_ENTITY_AND) 2590 { 2591 gcc_assert (mode >= 0 && mode <= 2); 2592 if (mode == 1) 2593 emit_move_insn (MACHINE_FUNCTION (cfun)->and_mask, 2594 gen_int_mode (0xfff1fffe, SImode)); 2595 return; 2596 } 2597 else if (entity == EPIPHANY_MSW_ENTITY_OR) 2598 { 2599 gcc_assert (mode >= 0 && mode <= 2); 2600 if (mode == 1) 2601 emit_move_insn (MACHINE_FUNCTION (cfun)->or_mask, GEN_INT(0x00080000)); 2602 return; 2603 } 2604 else if (entity == EPIPHANY_MSW_ENTITY_CONFIG) 2605 { 2606 /* Mode switching optimization is done after emit_initial_value_sets, 2607 so we have to take care of CONFIG_REGNUM here. */ 2608 gcc_assert (mode >= 0 && mode <= 2); 2609 rtx save = get_hard_reg_initial_val (SImode, CONFIG_REGNUM); 2610 if (mode == 1) 2611 emit_insn (gen_save_config (save)); 2612 return; 2613 } 2614 fp_mode = (enum attr_fp_mode) mode; 2615 src = NULL_RTX; 2616 2617 switch (fp_mode) 2618 { 2619 case FP_MODE_CALLER: 2620 /* The EPIPHANY_MSW_ENTITY_CONFIG processing must come later 2621 so that the config save gets inserted before the first use. */ 2622 gcc_assert (entity > EPIPHANY_MSW_ENTITY_CONFIG); 2623 src = get_hard_reg_initial_val (SImode, CONFIG_REGNUM); 2624 mask = MACHINE_FUNCTION (cfun)->and_mask; 2625 break; 2626 case FP_MODE_ROUND_UNKNOWN: 2627 MACHINE_FUNCTION (cfun)->unknown_mode_sets++; 2628 mask = MACHINE_FUNCTION (cfun)->and_mask; 2629 break; 2630 case FP_MODE_ROUND_NEAREST: 2631 if (entity == EPIPHANY_MSW_ENTITY_TRUNC) 2632 return; 2633 mask = MACHINE_FUNCTION (cfun)->and_mask; 2634 break; 2635 case FP_MODE_ROUND_TRUNC: 2636 if (entity == EPIPHANY_MSW_ENTITY_NEAREST) 2637 return; 2638 mask = MACHINE_FUNCTION (cfun)->and_mask; 2639 break; 2640 case FP_MODE_INT: 2641 mask = MACHINE_FUNCTION (cfun)->or_mask; 2642 break; 2643 case FP_MODE_NONE: 2644 default: 2645 gcc_unreachable (); 2646 } 2647 save_cc = gen_reg_rtx (CCmode); 2648 cc_reg = gen_rtx_REG (CCmode, CC_REGNUM); 2649 emit_move_insn (save_cc, cc_reg); 2650 mask = force_reg (SImode, mask); 2651 if (!src) 2652 { 2653 rtvec v = gen_rtvec (1, GEN_INT (fp_mode)); 2654 2655 src = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE)); 2656 } 2657 if (entity == EPIPHANY_MSW_ENTITY_ROUND_KNOWN 2658 || entity == EPIPHANY_MSW_ENTITY_FPU_OMNIBUS) 2659 src2 = copy_rtx (src); 2660 else 2661 { 2662 rtvec v = gen_rtvec (1, GEN_INT (FP_MODE_ROUND_UNKNOWN)); 2663 2664 src2 = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE)); 2665 } 2666 emit_insn (gen_set_fp_mode (src, src2, mask)); 2667 emit_move_insn (cc_reg, save_cc); 2668} 2669 2670void 2671epiphany_expand_set_fp_mode (rtx *operands) 2672{ 2673 rtx ctrl = gen_rtx_REG (SImode, CONFIG_REGNUM); 2674 rtx src = operands[0]; 2675 rtx mask_reg = operands[2]; 2676 rtx scratch = operands[3]; 2677 enum attr_fp_mode fp_mode; 2678 2679 2680 gcc_assert (rtx_equal_p (src, operands[1]) 2681 /* Sometimes reload gets silly and reloads the same pseudo 2682 into different registers. */ 2683 || (REG_P (src) && REG_P (operands[1]))); 2684 2685 if (!epiphany_uninterruptible_p (current_function_decl)) 2686 emit_insn (gen_gid ()); 2687 emit_move_insn (scratch, ctrl); 2688 2689 if (GET_CODE (src) == REG) 2690 { 2691 /* FP_MODE_CALLER */ 2692 emit_insn (gen_xorsi3 (scratch, scratch, src)); 2693 emit_insn (gen_andsi3 (scratch, scratch, mask_reg)); 2694 emit_insn (gen_xorsi3 (scratch, scratch, src)); 2695 } 2696 else 2697 { 2698 gcc_assert (GET_CODE (src) == CONST); 2699 src = XEXP (src, 0); 2700 fp_mode = (enum attr_fp_mode) INTVAL (XVECEXP (src, 0, 0)); 2701 switch (fp_mode) 2702 { 2703 case FP_MODE_ROUND_NEAREST: 2704 emit_insn (gen_andsi3 (scratch, scratch, mask_reg)); 2705 break; 2706 case FP_MODE_ROUND_TRUNC: 2707 emit_insn (gen_andsi3 (scratch, scratch, mask_reg)); 2708 emit_insn (gen_add2_insn (scratch, const1_rtx)); 2709 break; 2710 case FP_MODE_INT: 2711 emit_insn (gen_iorsi3 (scratch, scratch, mask_reg)); 2712 break; 2713 case FP_MODE_CALLER: 2714 case FP_MODE_ROUND_UNKNOWN: 2715 case FP_MODE_NONE: 2716 gcc_unreachable (); 2717 } 2718 } 2719 emit_move_insn (ctrl, scratch); 2720 if (!epiphany_uninterruptible_p (current_function_decl)) 2721 emit_insn (gen_gie ()); 2722} 2723 2724void 2725epiphany_insert_mode_switch_use (rtx_insn *insn, 2726 int entity ATTRIBUTE_UNUSED, 2727 int mode ATTRIBUTE_UNUSED) 2728{ 2729 rtx pat = PATTERN (insn); 2730 rtvec v; 2731 int len, i; 2732 rtx near = gen_rtx_REG (SImode, FP_NEAREST_REGNUM); 2733 rtx trunc = gen_rtx_REG (SImode, FP_TRUNCATE_REGNUM); 2734 2735 if (entity != EPIPHANY_MSW_ENTITY_FPU_OMNIBUS) 2736 return; 2737 switch ((enum attr_fp_mode) get_attr_fp_mode (insn)) 2738 { 2739 case FP_MODE_ROUND_NEAREST: 2740 near = gen_rtx_USE (VOIDmode, near); 2741 trunc = gen_rtx_CLOBBER (VOIDmode, trunc); 2742 break; 2743 case FP_MODE_ROUND_TRUNC: 2744 near = gen_rtx_CLOBBER (VOIDmode, near); 2745 trunc = gen_rtx_USE (VOIDmode, trunc); 2746 break; 2747 case FP_MODE_ROUND_UNKNOWN: 2748 near = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FP_ANYFP_REGNUM)); 2749 trunc = copy_rtx (near); 2750 /* Fall through. */ 2751 case FP_MODE_INT: 2752 case FP_MODE_CALLER: 2753 near = gen_rtx_USE (VOIDmode, near); 2754 trunc = gen_rtx_USE (VOIDmode, trunc); 2755 break; 2756 case FP_MODE_NONE: 2757 gcc_unreachable (); 2758 } 2759 gcc_assert (GET_CODE (pat) == PARALLEL); 2760 len = XVECLEN (pat, 0); 2761 v = rtvec_alloc (len + 2); 2762 for (i = 0; i < len; i++) 2763 RTVEC_ELT (v, i) = XVECEXP (pat, 0, i); 2764 RTVEC_ELT (v, len) = near; 2765 RTVEC_ELT (v, len + 1) = trunc; 2766 pat = gen_rtx_PARALLEL (VOIDmode, v); 2767 PATTERN (insn) = pat; 2768 MACHINE_FUNCTION (cfun)->control_use_inserted = true; 2769} 2770 2771bool 2772epiphany_epilogue_uses (int regno) 2773{ 2774 if (regno == GPR_LR) 2775 return true; 2776 if (reload_completed && epiphany_is_interrupt_p (current_function_decl)) 2777 { 2778 if (fixed_regs[regno] 2779 && regno != STATUS_REGNUM && regno != IRET_REGNUM 2780 && regno != FP_NEAREST_REGNUM && regno != FP_TRUNCATE_REGNUM) 2781 return false; 2782 return true; 2783 } 2784 if (regno == FP_NEAREST_REGNUM 2785 && epiphany_normal_fp_mode != FP_MODE_ROUND_TRUNC) 2786 return true; 2787 if (regno == FP_TRUNCATE_REGNUM 2788 && epiphany_normal_fp_mode != FP_MODE_ROUND_NEAREST) 2789 return true; 2790 return false; 2791} 2792 2793static unsigned int 2794epiphany_min_divisions_for_recip_mul (machine_mode mode) 2795{ 2796 if (flag_reciprocal_math && mode == SFmode) 2797 /* We'll expand into a multiply-by-reciprocal anyway, so we might a well do 2798 it already at the tree level and expose it to further optimizations. */ 2799 return 1; 2800 return default_min_divisions_for_recip_mul (mode); 2801} 2802 2803static machine_mode 2804epiphany_preferred_simd_mode (machine_mode mode ATTRIBUTE_UNUSED) 2805{ 2806 return TARGET_VECT_DOUBLE ? DImode : SImode; 2807} 2808 2809static bool 2810epiphany_vector_mode_supported_p (machine_mode mode) 2811{ 2812 if (mode == V2SFmode) 2813 return true; 2814 if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT 2815 && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8)) 2816 return true; 2817 return false; 2818} 2819 2820static bool 2821epiphany_vector_alignment_reachable (const_tree type, bool is_packed) 2822{ 2823 /* Vectors which aren't in packed structures will not be less aligned than 2824 the natural alignment of their element type, so this is safe. */ 2825 if (TYPE_ALIGN_UNIT (type) == 4) 2826 return !is_packed; 2827 2828 return default_builtin_vector_alignment_reachable (type, is_packed); 2829} 2830 2831static bool 2832epiphany_support_vector_misalignment (machine_mode mode, const_tree type, 2833 int misalignment, bool is_packed) 2834{ 2835 if (GET_MODE_SIZE (mode) == 8 && misalignment % 4 == 0) 2836 return true; 2837 return default_builtin_support_vector_misalignment (mode, type, misalignment, 2838 is_packed); 2839} 2840 2841/* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small 2842 structs. Make structs double-word-aligned it they are a double word or 2843 (potentially) larger; failing that, do the same for a size of 32 bits. */ 2844unsigned 2845epiphany_special_round_type_align (tree type, unsigned computed, 2846 unsigned specified) 2847{ 2848 unsigned align = MAX (computed, specified); 2849 tree field; 2850 HOST_WIDE_INT total, max; 2851 unsigned try_align = FASTEST_ALIGNMENT; 2852 2853 if (maximum_field_alignment && try_align > maximum_field_alignment) 2854 try_align = maximum_field_alignment; 2855 if (align >= try_align) 2856 return align; 2857 for (max = 0, field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) 2858 { 2859 tree offset, size; 2860 2861 if (TREE_CODE (field) != FIELD_DECL 2862 || TREE_TYPE (field) == error_mark_node) 2863 continue; 2864 offset = bit_position (field); 2865 size = DECL_SIZE (field); 2866 if (!tree_fits_uhwi_p (offset) || !tree_fits_uhwi_p (size) 2867 || tree_to_uhwi (offset) >= try_align 2868 || tree_to_uhwi (size) >= try_align) 2869 return try_align; 2870 total = tree_to_uhwi (offset) + tree_to_uhwi (size); 2871 if (total > max) 2872 max = total; 2873 } 2874 if (max >= (HOST_WIDE_INT) try_align) 2875 align = try_align; 2876 else if (try_align > 32 && max >= 32) 2877 align = max > 32 ? 64 : 32; 2878 return align; 2879} 2880 2881/* Upping the alignment of arrays in structs is not only a performance 2882 enhancement, it also helps preserve assumptions about how 2883 arrays-at-the-end-of-structs work, like for struct gcov_fn_info in 2884 libgcov.c . */ 2885unsigned 2886epiphany_adjust_field_align (tree field, unsigned computed) 2887{ 2888 if (computed == 32 2889 && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE) 2890 { 2891 tree elmsz = TYPE_SIZE (TREE_TYPE (TREE_TYPE (field))); 2892 2893 if (!tree_fits_uhwi_p (elmsz) || tree_to_uhwi (elmsz) >= 32) 2894 return 64; 2895 } 2896 return computed; 2897} 2898 2899/* Output code to add DELTA to the first argument, and then jump 2900 to FUNCTION. Used for C++ multiple inheritance. */ 2901static void 2902epiphany_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, 2903 HOST_WIDE_INT delta, 2904 HOST_WIDE_INT vcall_offset, 2905 tree function) 2906{ 2907 int this_regno 2908 = aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? 1 : 0; 2909 const char *this_name = reg_names[this_regno]; 2910 const char *fname; 2911 2912 /* We use IP and R16 as a scratch registers. */ 2913 gcc_assert (call_used_regs [GPR_IP]); 2914 gcc_assert (call_used_regs [GPR_16]); 2915 2916 /* Add DELTA. When possible use a plain add, otherwise load it into 2917 a register first. */ 2918 if (delta == 0) 2919 ; /* Done. */ 2920 else if (SIMM11 (delta)) 2921 asm_fprintf (file, "\tadd\t%s,%s,%d\n", this_name, this_name, (int) delta); 2922 else if (delta < 0 && delta >= -0xffff) 2923 { 2924 asm_fprintf (file, "\tmov\tip,%d\n", (int) -delta); 2925 asm_fprintf (file, "\tsub\t%s,%s,ip\n", this_name, this_name); 2926 } 2927 else 2928 { 2929 asm_fprintf (file, "\tmov\tip,%%low(%ld)\n", (long) delta); 2930 if (delta & ~0xffff) 2931 asm_fprintf (file, "\tmovt\tip,%%high(%ld)\n", (long) delta); 2932 asm_fprintf (file, "\tadd\t%s,%s,ip\n", this_name, this_name); 2933 } 2934 2935 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */ 2936 if (vcall_offset != 0) 2937 { 2938 /* ldr ip,[this] --> temp = *this 2939 ldr ip,[ip,vcall_offset] > temp = *(*this + vcall_offset) 2940 add this,this,ip --> this+ = *(*this + vcall_offset) */ 2941 asm_fprintf (file, "\tldr\tip, [%s]\n", this_name); 2942 if (vcall_offset < -0x7ff * 4 || vcall_offset > 0x7ff * 4 2943 || (vcall_offset & 3) != 0) 2944 { 2945 asm_fprintf (file, "\tmov\tr16, %%low(%ld)\n", (long) vcall_offset); 2946 asm_fprintf (file, "\tmovt\tr16, %%high(%ld)\n", (long) vcall_offset); 2947 asm_fprintf (file, "\tldr\tip, [ip,r16]\n"); 2948 } 2949 else 2950 asm_fprintf (file, "\tldr\tip, [ip,%d]\n", (int) vcall_offset / 4); 2951 asm_fprintf (file, "\tadd\t%s, %s, ip\n", this_name, this_name); 2952 } 2953 2954 fname = XSTR (XEXP (DECL_RTL (function), 0), 0); 2955 if (epiphany_is_long_call_p (XEXP (DECL_RTL (function), 0))) 2956 { 2957 fputs ("\tmov\tip,%low(", file); 2958 assemble_name (file, fname); 2959 fputs (")\n\tmovt\tip,%high(", file); 2960 assemble_name (file, fname); 2961 fputs (")\n\tjr ip\n", file); 2962 } 2963 else 2964 { 2965 fputs ("\tb\t", file); 2966 assemble_name (file, fname); 2967 fputc ('\n', file); 2968 } 2969} 2970 2971void 2972epiphany_start_function (FILE *file, const char *name, tree decl) 2973{ 2974 /* If the function doesn't fit into the on-chip memory, it will have a 2975 section attribute - or lack of it - that denotes it goes somewhere else. 2976 But the architecture spec says that an interrupt vector still has to 2977 point to on-chip memory. So we must place a jump there to get to the 2978 actual function implementation. The forwarder_section attribute 2979 specifies the section where this jump goes. 2980 This mechanism can also be useful to have a shortcall destination for 2981 a function that is actually placed much farther away. */ 2982 tree attrs, int_attr, int_names, int_name, forwarder_attr; 2983 2984 attrs = DECL_ATTRIBUTES (decl); 2985 int_attr = lookup_attribute ("interrupt", attrs); 2986 if (int_attr) 2987 for (int_names = TREE_VALUE (int_attr); int_names; 2988 int_names = TREE_CHAIN (int_names)) 2989 { 2990 char buf[99]; 2991 2992 int_name = TREE_VALUE (int_names); 2993 sprintf (buf, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name)); 2994 switch_to_section (get_section (buf, SECTION_CODE, decl)); 2995 fputs ("\tb\t", file); 2996 assemble_name (file, name); 2997 fputc ('\n', file); 2998 } 2999 forwarder_attr = lookup_attribute ("forwarder_section", attrs); 3000 if (forwarder_attr) 3001 { 3002 const char *prefix = "__forwarder_dst_"; 3003 char *dst_name = (char *) alloca (strlen (prefix) + strlen (name) + 1); 3004 3005 strcpy (dst_name, prefix); 3006 strcat (dst_name, name); 3007 forwarder_attr = TREE_VALUE (TREE_VALUE (forwarder_attr)); 3008 switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr), 3009 SECTION_CODE, decl)); 3010 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl); 3011 if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl), 0))) 3012 { 3013 int tmp = GPR_0; 3014 3015 if (int_attr) 3016 fputs ("\tstrd r0,[sp,-1]\n", file); 3017 else 3018 tmp = GPR_16; 3019 gcc_assert (call_used_regs[tmp]); 3020 fprintf (file, "\tmov r%d,%%low(", tmp); 3021 assemble_name (file, dst_name); 3022 fprintf (file, ")\n" 3023 "\tmovt r%d,%%high(", tmp); 3024 assemble_name (file, dst_name); 3025 fprintf (file, ")\n" 3026 "\tjr r%d\n", tmp); 3027 } 3028 else 3029 { 3030 fputs ("\tb\t", file); 3031 assemble_name (file, dst_name); 3032 fputc ('\n', file); 3033 } 3034 name = dst_name; 3035 } 3036 switch_to_section (function_section (decl)); 3037 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl); 3038} 3039 3040struct gcc_target targetm = TARGET_INITIALIZER; 3041