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