mmix.c revision 1.10
1/* Definitions of target machine for GNU compiler, for MMIX. 2 Copyright (C) 2000-2019 Free Software Foundation, Inc. 3 Contributed by Hans-Peter Nilsson (hp@bitrange.com) 4 5This file is part of GCC. 6 7GCC is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 3, or (at your option) 10any later version. 11 12GCC is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with GCC; see the file COPYING3. If not see 19<http://www.gnu.org/licenses/>. */ 20 21#define IN_TARGET_CODE 1 22 23#include "config.h" 24#include "system.h" 25#include "coretypes.h" 26#include "backend.h" 27#include "target.h" 28#include "rtl.h" 29#include "tree.h" 30#include "stringpool.h" 31#include "attribs.h" 32#include "df.h" 33#include "memmodel.h" 34#include "tm_p.h" 35#include "insn-config.h" 36#include "optabs.h" 37#include "regs.h" 38#include "emit-rtl.h" 39#include "recog.h" 40#include "diagnostic-core.h" 41#include "output.h" 42#include "varasm.h" 43#include "stor-layout.h" 44#include "calls.h" 45#include "explow.h" 46#include "expr.h" 47#include "dwarf2.h" 48#include "tm-constrs.h" 49#include "builtins.h" 50 51/* This file should be included last. */ 52#include "target-def.h" 53 54/* First some local helper definitions. */ 55#define MMIX_FIRST_GLOBAL_REGNUM 32 56 57/* We'd need a current_function_has_landing_pad. It's marked as such when 58 a nonlocal_goto_receiver is expanded. Not just a C++ thing, but 59 mostly. */ 60#define MMIX_CFUN_HAS_LANDING_PAD (cfun->machine->has_landing_pad != 0) 61 62/* We have no means to tell DWARF 2 about the register stack, so we need 63 to store the return address on the stack if an exception can get into 64 this function. We'll have an "initial value" recorded for the 65 return-register if we've seen a call instruction emitted. This note 66 will be inaccurate before instructions are emitted, but the only caller 67 at that time is looking for modulo from stack-boundary, to which the 68 return-address does not contribute, and which is always 0 for MMIX 69 anyway. Beware of calling leaf_function_p here, as it'll abort if 70 called within a sequence. */ 71#define MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS \ 72 (flag_exceptions \ 73 && has_hard_reg_initial_val (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM)) 74 75#define IS_MMIX_EH_RETURN_DATA_REG(REGNO) \ 76 (crtl->calls_eh_return \ 77 && (EH_RETURN_DATA_REGNO (0) == REGNO \ 78 || EH_RETURN_DATA_REGNO (1) == REGNO \ 79 || EH_RETURN_DATA_REGNO (2) == REGNO \ 80 || EH_RETURN_DATA_REGNO (3) == REGNO)) 81 82/* For the default ABI, we rename registers at output-time to fill the gap 83 between the (statically partitioned) saved registers and call-clobbered 84 registers. In effect this makes unused call-saved registers to be used 85 as call-clobbered registers. The benefit comes from keeping the number 86 of local registers (value of rL) low, since there's a cost of 87 increasing rL and clearing unused (unset) registers with lower numbers. 88 Don't translate while outputting the prologue. */ 89#define MMIX_OUTPUT_REGNO(N) \ 90 (TARGET_ABI_GNU \ 91 || (int) (N) < MMIX_RETURN_VALUE_REGNUM \ 92 || (int) (N) > MMIX_LAST_STACK_REGISTER_REGNUM \ 93 || cfun == NULL \ 94 || cfun->machine == NULL \ 95 || cfun->machine->in_prologue \ 96 ? (N) : ((N) - MMIX_RETURN_VALUE_REGNUM \ 97 + cfun->machine->highest_saved_stack_register + 1)) 98 99/* The %d in "POP %d,0". */ 100#define MMIX_POP_ARGUMENT() \ 101 ((! TARGET_ABI_GNU \ 102 && crtl->return_rtx != NULL \ 103 && ! cfun->returns_struct) \ 104 ? (GET_CODE (crtl->return_rtx) == PARALLEL \ 105 ? GET_NUM_ELEM (XVEC (crtl->return_rtx, 0)) : 1) \ 106 : 0) 107 108/* The canonical saved comparison operands for non-cc0 machines, set in 109 the compare expander. */ 110rtx mmix_compare_op0; 111rtx mmix_compare_op1; 112 113/* Declarations of locals. */ 114 115/* Intermediate for insn output. */ 116static int mmix_output_destination_register; 117 118static void mmix_option_override (void); 119static void mmix_asm_output_source_filename (FILE *, const char *); 120static void mmix_output_shiftvalue_op_from_str 121 (FILE *, const char *, int64_t); 122static void mmix_output_shifted_value (FILE *, int64_t); 123static void mmix_output_condition (FILE *, const_rtx, int); 124static void mmix_output_octa (FILE *, int64_t, int); 125static bool mmix_assemble_integer (rtx, unsigned int, int); 126static struct machine_function *mmix_init_machine_status (void); 127static void mmix_encode_section_info (tree, rtx, int); 128static const char *mmix_strip_name_encoding (const char *); 129static void mmix_emit_sp_add (HOST_WIDE_INT offset); 130static void mmix_target_asm_function_prologue (FILE *); 131static void mmix_target_asm_function_end_prologue (FILE *); 132static void mmix_target_asm_function_epilogue (FILE *); 133static reg_class_t mmix_preferred_reload_class (rtx, reg_class_t); 134static reg_class_t mmix_preferred_output_reload_class (rtx, reg_class_t); 135static bool mmix_legitimate_address_p (machine_mode, rtx, bool); 136static bool mmix_legitimate_constant_p (machine_mode, rtx); 137static void mmix_reorg (void); 138static void mmix_asm_output_mi_thunk 139 (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree); 140static void mmix_setup_incoming_varargs 141 (cumulative_args_t, machine_mode, tree, int *, int); 142static void mmix_file_start (void); 143static void mmix_file_end (void); 144static void mmix_init_libfuncs (void); 145static bool mmix_rtx_costs (rtx, machine_mode, int, int, int *, bool); 146static int mmix_register_move_cost (machine_mode, 147 reg_class_t, reg_class_t); 148static rtx mmix_struct_value_rtx (tree, int); 149static machine_mode mmix_promote_function_mode (const_tree, 150 machine_mode, 151 int *, const_tree, int); 152static void mmix_function_arg_advance (cumulative_args_t, machine_mode, 153 const_tree, bool); 154static rtx mmix_function_arg_1 (const cumulative_args_t, machine_mode, 155 const_tree, bool, bool); 156static rtx mmix_function_incoming_arg (cumulative_args_t, machine_mode, 157 const_tree, bool); 158static rtx mmix_function_arg (cumulative_args_t, machine_mode, 159 const_tree, bool); 160static rtx mmix_function_value (const_tree, const_tree, bool); 161static rtx mmix_libcall_value (machine_mode, const_rtx); 162static bool mmix_function_value_regno_p (const unsigned int); 163static bool mmix_pass_by_reference (cumulative_args_t, 164 machine_mode, const_tree, bool); 165static bool mmix_frame_pointer_required (void); 166static void mmix_asm_trampoline_template (FILE *); 167static void mmix_trampoline_init (rtx, tree, rtx); 168static void mmix_print_operand (FILE *, rtx, int); 169static void mmix_print_operand_address (FILE *, machine_mode, rtx); 170static bool mmix_print_operand_punct_valid_p (unsigned char); 171static void mmix_conditional_register_usage (void); 172static HOST_WIDE_INT mmix_static_rtx_alignment (machine_mode); 173static HOST_WIDE_INT mmix_constant_alignment (const_tree, HOST_WIDE_INT); 174static HOST_WIDE_INT mmix_starting_frame_offset (void); 175 176/* Target structure macros. Listed by node. See `Using and Porting GCC' 177 for a general description. */ 178 179/* Node: Function Entry */ 180 181#undef TARGET_ASM_BYTE_OP 182#define TARGET_ASM_BYTE_OP NULL 183#undef TARGET_ASM_ALIGNED_HI_OP 184#define TARGET_ASM_ALIGNED_HI_OP NULL 185#undef TARGET_ASM_ALIGNED_SI_OP 186#define TARGET_ASM_ALIGNED_SI_OP NULL 187#undef TARGET_ASM_ALIGNED_DI_OP 188#define TARGET_ASM_ALIGNED_DI_OP NULL 189#undef TARGET_ASM_INTEGER 190#define TARGET_ASM_INTEGER mmix_assemble_integer 191 192#undef TARGET_ASM_FUNCTION_PROLOGUE 193#define TARGET_ASM_FUNCTION_PROLOGUE mmix_target_asm_function_prologue 194 195#undef TARGET_ASM_FUNCTION_END_PROLOGUE 196#define TARGET_ASM_FUNCTION_END_PROLOGUE mmix_target_asm_function_end_prologue 197 198#undef TARGET_ASM_FUNCTION_EPILOGUE 199#define TARGET_ASM_FUNCTION_EPILOGUE mmix_target_asm_function_epilogue 200 201#undef TARGET_PRINT_OPERAND 202#define TARGET_PRINT_OPERAND mmix_print_operand 203#undef TARGET_PRINT_OPERAND_ADDRESS 204#define TARGET_PRINT_OPERAND_ADDRESS mmix_print_operand_address 205#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P 206#define TARGET_PRINT_OPERAND_PUNCT_VALID_P mmix_print_operand_punct_valid_p 207 208#undef TARGET_ENCODE_SECTION_INFO 209#define TARGET_ENCODE_SECTION_INFO mmix_encode_section_info 210#undef TARGET_STRIP_NAME_ENCODING 211#define TARGET_STRIP_NAME_ENCODING mmix_strip_name_encoding 212 213#undef TARGET_ASM_OUTPUT_MI_THUNK 214#define TARGET_ASM_OUTPUT_MI_THUNK mmix_asm_output_mi_thunk 215#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK 216#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall 217#undef TARGET_ASM_FILE_START 218#define TARGET_ASM_FILE_START mmix_file_start 219#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE 220#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true 221#undef TARGET_ASM_FILE_END 222#define TARGET_ASM_FILE_END mmix_file_end 223#undef TARGET_ASM_OUTPUT_SOURCE_FILENAME 224#define TARGET_ASM_OUTPUT_SOURCE_FILENAME mmix_asm_output_source_filename 225 226#undef TARGET_INIT_LIBFUNCS 227#define TARGET_INIT_LIBFUNCS mmix_init_libfuncs 228 229#undef TARGET_CONDITIONAL_REGISTER_USAGE 230#define TARGET_CONDITIONAL_REGISTER_USAGE mmix_conditional_register_usage 231 232#undef TARGET_HAVE_SPECULATION_SAFE_VALUE 233#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed 234 235#undef TARGET_RTX_COSTS 236#define TARGET_RTX_COSTS mmix_rtx_costs 237#undef TARGET_ADDRESS_COST 238#define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0 239 240#undef TARGET_REGISTER_MOVE_COST 241#define TARGET_REGISTER_MOVE_COST mmix_register_move_cost 242 243#undef TARGET_MACHINE_DEPENDENT_REORG 244#define TARGET_MACHINE_DEPENDENT_REORG mmix_reorg 245 246#undef TARGET_PROMOTE_FUNCTION_MODE 247#define TARGET_PROMOTE_FUNCTION_MODE mmix_promote_function_mode 248 249#undef TARGET_FUNCTION_VALUE 250#define TARGET_FUNCTION_VALUE mmix_function_value 251#undef TARGET_LIBCALL_VALUE 252#define TARGET_LIBCALL_VALUE mmix_libcall_value 253#undef TARGET_FUNCTION_VALUE_REGNO_P 254#define TARGET_FUNCTION_VALUE_REGNO_P mmix_function_value_regno_p 255 256#undef TARGET_FUNCTION_ARG 257#define TARGET_FUNCTION_ARG mmix_function_arg 258#undef TARGET_FUNCTION_INCOMING_ARG 259#define TARGET_FUNCTION_INCOMING_ARG mmix_function_incoming_arg 260#undef TARGET_FUNCTION_ARG_ADVANCE 261#define TARGET_FUNCTION_ARG_ADVANCE mmix_function_arg_advance 262#undef TARGET_STRUCT_VALUE_RTX 263#define TARGET_STRUCT_VALUE_RTX mmix_struct_value_rtx 264#undef TARGET_SETUP_INCOMING_VARARGS 265#define TARGET_SETUP_INCOMING_VARARGS mmix_setup_incoming_varargs 266#undef TARGET_PASS_BY_REFERENCE 267#define TARGET_PASS_BY_REFERENCE mmix_pass_by_reference 268#undef TARGET_CALLEE_COPIES 269#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true 270 271#undef TARGET_PREFERRED_RELOAD_CLASS 272#define TARGET_PREFERRED_RELOAD_CLASS mmix_preferred_reload_class 273#undef TARGET_PREFERRED_OUTPUT_RELOAD_CLASS 274#define TARGET_PREFERRED_OUTPUT_RELOAD_CLASS mmix_preferred_output_reload_class 275 276#undef TARGET_LRA_P 277#define TARGET_LRA_P hook_bool_void_false 278 279#undef TARGET_LEGITIMATE_ADDRESS_P 280#define TARGET_LEGITIMATE_ADDRESS_P mmix_legitimate_address_p 281#undef TARGET_LEGITIMATE_CONSTANT_P 282#define TARGET_LEGITIMATE_CONSTANT_P mmix_legitimate_constant_p 283 284#undef TARGET_FRAME_POINTER_REQUIRED 285#define TARGET_FRAME_POINTER_REQUIRED mmix_frame_pointer_required 286 287#undef TARGET_ASM_TRAMPOLINE_TEMPLATE 288#define TARGET_ASM_TRAMPOLINE_TEMPLATE mmix_asm_trampoline_template 289#undef TARGET_TRAMPOLINE_INIT 290#define TARGET_TRAMPOLINE_INIT mmix_trampoline_init 291 292#undef TARGET_OPTION_OVERRIDE 293#define TARGET_OPTION_OVERRIDE mmix_option_override 294 295#undef TARGET_STATIC_RTX_ALIGNMENT 296#define TARGET_STATIC_RTX_ALIGNMENT mmix_static_rtx_alignment 297#undef TARGET_CONSTANT_ALIGNMENT 298#define TARGET_CONSTANT_ALIGNMENT mmix_constant_alignment 299 300#undef TARGET_STARTING_FRAME_OFFSET 301#define TARGET_STARTING_FRAME_OFFSET mmix_starting_frame_offset 302 303struct gcc_target targetm = TARGET_INITIALIZER; 304 305/* Functions that are expansions for target macros. 306 See Target Macros in `Using and Porting GCC'. */ 307 308/* TARGET_OPTION_OVERRIDE. */ 309 310static void 311mmix_option_override (void) 312{ 313 /* Should we err or should we warn? Hmm. At least we must neutralize 314 it. For example the wrong kind of case-tables will be generated with 315 PIC; we use absolute address items for mmixal compatibility. FIXME: 316 They could be relative if we just elide them to after all pertinent 317 labels. */ 318 if (flag_pic) 319 { 320 warning (0, "%<-f%s%> not supported: ignored", 321 (flag_pic > 1) ? "PIC" : "pic"); 322 flag_pic = 0; 323 } 324} 325 326/* INIT_EXPANDERS. */ 327 328void 329mmix_init_expanders (void) 330{ 331 init_machine_status = mmix_init_machine_status; 332} 333 334/* Set the per-function data. */ 335 336static struct machine_function * 337mmix_init_machine_status (void) 338{ 339 return ggc_cleared_alloc<machine_function> (); 340} 341 342/* DATA_ABI_ALIGNMENT. 343 We have trouble getting the address of stuff that is located at other 344 than 32-bit alignments (GETA requirements), so try to give everything 345 at least 32-bit alignment. */ 346 347int 348mmix_data_alignment (tree type ATTRIBUTE_UNUSED, int basic_align) 349{ 350 if (basic_align < 32) 351 return 32; 352 353 return basic_align; 354} 355 356/* Implement TARGET_STATIC_RTX_ALIGNMENT. */ 357 358static HOST_WIDE_INT 359mmix_static_rtx_alignment (machine_mode mode) 360{ 361 return MAX (GET_MODE_ALIGNMENT (mode), 32); 362} 363 364/* Implement tARGET_CONSTANT_ALIGNMENT. */ 365 366static HOST_WIDE_INT 367mmix_constant_alignment (const_tree, HOST_WIDE_INT basic_align) 368{ 369 if (basic_align < 32) 370 return 32; 371 372 return basic_align; 373} 374 375/* LOCAL_ALIGNMENT. */ 376 377unsigned 378mmix_local_alignment (tree type ATTRIBUTE_UNUSED, unsigned basic_align) 379{ 380 if (basic_align < 32) 381 return 32; 382 383 return basic_align; 384} 385 386/* TARGET_CONDITIONAL_REGISTER_USAGE. */ 387 388static void 389mmix_conditional_register_usage (void) 390{ 391 int i; 392 393 if (TARGET_ABI_GNU) 394 { 395 static const int gnu_abi_reg_alloc_order[] 396 = MMIX_GNU_ABI_REG_ALLOC_ORDER; 397 398 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 399 reg_alloc_order[i] = gnu_abi_reg_alloc_order[i]; 400 401 /* Change the default from the mmixware ABI. For the GNU ABI, 402 $15..$30 are call-saved just as $0..$14. There must be one 403 call-clobbered local register for the "hole" that holds the 404 number of saved local registers saved by PUSHJ/PUSHGO during the 405 function call, receiving the return value at return. So best is 406 to use the highest, $31. It's already marked call-clobbered for 407 the mmixware ABI. */ 408 for (i = 15; i <= 30; i++) 409 call_used_regs[i] = 0; 410 411 /* "Unfix" the parameter registers. */ 412 for (i = MMIX_RESERVED_GNU_ARG_0_REGNUM; 413 i < MMIX_RESERVED_GNU_ARG_0_REGNUM + MMIX_MAX_ARGS_IN_REGS; 414 i++) 415 fixed_regs[i] = 0; 416 } 417 418 /* Step over the ":" in special register names. */ 419 if (! TARGET_TOPLEVEL_SYMBOLS) 420 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 421 if (reg_names[i][0] == ':') 422 reg_names[i]++; 423} 424 425/* INCOMING_REGNO and OUTGOING_REGNO worker function. 426 Those two macros must only be applied to function argument 427 registers and the function return value register for the opposite 428 use. FIXME: for their current use in gcc, it'd be better with an 429 explicit specific additional FUNCTION_INCOMING_ARG_REGNO_P a'la 430 TARGET_FUNCTION_ARG / TARGET_FUNCTION_INCOMING_ARG instead of 431 forcing the target to commit to a fixed mapping and for any 432 unspecified register use. Particularly when thinking about the 433 return-value, it is better to imagine INCOMING_REGNO and 434 OUTGOING_REGNO as named CALLEE_TO_CALLER_REGNO and INNER_REGNO as 435 named CALLER_TO_CALLEE_REGNO because the direction. The "incoming" 436 and "outgoing" is from the perspective of the parameter-registers, 437 but the same macro is (must be, lacking an alternative like 438 suggested above) used to map the return-value-register from the 439 same perspective. To make directions even more confusing, the macro 440 MMIX_OUTGOING_RETURN_VALUE_REGNUM holds the number of the register 441 in which to return a value, i.e. INCOMING_REGNO for the return-value- 442 register as received from a called function; the return-value on the 443 way out. */ 444 445int 446mmix_opposite_regno (int regno, int incoming) 447{ 448 if (incoming && regno == MMIX_OUTGOING_RETURN_VALUE_REGNUM) 449 return MMIX_RETURN_VALUE_REGNUM; 450 451 if (!incoming && regno == MMIX_RETURN_VALUE_REGNUM) 452 return MMIX_OUTGOING_RETURN_VALUE_REGNUM; 453 454 if (!mmix_function_arg_regno_p (regno, incoming)) 455 return regno; 456 457 return 458 regno - (incoming 459 ? MMIX_FIRST_INCOMING_ARG_REGNUM - MMIX_FIRST_ARG_REGNUM 460 : MMIX_FIRST_ARG_REGNUM - MMIX_FIRST_INCOMING_ARG_REGNUM); 461} 462 463/* LOCAL_REGNO. 464 All registers that are part of the register stack and that will be 465 saved are local. */ 466 467int 468mmix_local_regno (int regno) 469{ 470 return regno <= MMIX_LAST_STACK_REGISTER_REGNUM && !call_used_regs[regno]; 471} 472 473/* TARGET_PREFERRED_RELOAD_CLASS. 474 We need to extend the reload class of REMAINDER_REG and HIMULT_REG. */ 475 476static reg_class_t 477mmix_preferred_reload_class (rtx x, reg_class_t rclass) 478{ 479 /* FIXME: Revisit. */ 480 return GET_CODE (x) == MOD && GET_MODE (x) == DImode 481 ? REMAINDER_REG : rclass; 482} 483 484/* TARGET_PREFERRED_OUTPUT_RELOAD_CLASS. 485 We need to extend the reload class of REMAINDER_REG and HIMULT_REG. */ 486 487static reg_class_t 488mmix_preferred_output_reload_class (rtx x, reg_class_t rclass) 489{ 490 /* FIXME: Revisit. */ 491 return GET_CODE (x) == MOD && GET_MODE (x) == DImode 492 ? REMAINDER_REG : rclass; 493} 494 495/* SECONDARY_RELOAD_CLASS. 496 We need to reload regs of REMAINDER_REG and HIMULT_REG elsewhere. */ 497 498enum reg_class 499mmix_secondary_reload_class (enum reg_class rclass, 500 machine_mode mode ATTRIBUTE_UNUSED, 501 rtx x ATTRIBUTE_UNUSED, 502 int in_p ATTRIBUTE_UNUSED) 503{ 504 if (rclass == REMAINDER_REG 505 || rclass == HIMULT_REG 506 || rclass == SYSTEM_REGS) 507 return GENERAL_REGS; 508 509 return NO_REGS; 510} 511 512/* DYNAMIC_CHAIN_ADDRESS. */ 513 514rtx 515mmix_dynamic_chain_address (rtx frame) 516{ 517 /* FIXME: the frame-pointer is stored at offset -8 from the current 518 frame-pointer. Unfortunately, the caller assumes that a 519 frame-pointer is present for *all* previous frames. There should be 520 a way to say that that cannot be done, like for RETURN_ADDR_RTX. */ 521 return plus_constant (Pmode, frame, -8); 522} 523 524/* Implement TARGET_STARTING_FRAME_OFFSET. */ 525 526static HOST_WIDE_INT 527mmix_starting_frame_offset (void) 528{ 529 /* The old frame pointer is in the slot below the new one, so 530 FIRST_PARM_OFFSET does not need to depend on whether the 531 frame-pointer is needed or not. We have to adjust for the register 532 stack pointer being located below the saved frame pointer. 533 Similarly, we store the return address on the stack too, for 534 exception handling, and always if we save the register stack pointer. */ 535 return 536 (-8 537 + (MMIX_CFUN_HAS_LANDING_PAD 538 ? -16 : (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS ? -8 : 0))); 539} 540 541/* RETURN_ADDR_RTX. */ 542 543rtx 544mmix_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED) 545{ 546 return count == 0 547 ? (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS 548 /* FIXME: Set frame_alias_set on the following. (Why?) 549 See mmix_initial_elimination_offset for the reason we can't use 550 get_hard_reg_initial_val for both. Always using a stack slot 551 and not a register would be suboptimal. */ 552 ? validize_mem (gen_rtx_MEM (Pmode, 553 plus_constant (Pmode, 554 frame_pointer_rtx, -16))) 555 : get_hard_reg_initial_val (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM)) 556 : NULL_RTX; 557} 558 559/* SETUP_FRAME_ADDRESSES. */ 560 561void 562mmix_setup_frame_addresses (void) 563{ 564 /* Nothing needed at the moment. */ 565} 566 567/* The difference between the (imaginary) frame pointer and the stack 568 pointer. Used to eliminate the frame pointer. */ 569 570int 571mmix_initial_elimination_offset (int fromreg, int toreg) 572{ 573 int regno; 574 int fp_sp_offset 575 = (get_frame_size () + crtl->outgoing_args_size + 7) & ~7; 576 577 /* There is no actual offset between these two virtual values, but for 578 the frame-pointer, we have the old one in the stack position below 579 it, so the offset for the frame-pointer to the stack-pointer is one 580 octabyte larger. */ 581 if (fromreg == MMIX_ARG_POINTER_REGNUM 582 && toreg == MMIX_FRAME_POINTER_REGNUM) 583 return 0; 584 585 /* The difference is the size of local variables plus the size of 586 outgoing function arguments that would normally be passed as 587 registers but must be passed on stack because we're out of 588 function-argument registers. Only global saved registers are 589 counted; the others go on the register stack. 590 591 The frame-pointer is counted too if it is what is eliminated, as we 592 need to balance the offset for it from TARGET_STARTING_FRAME_OFFSET. 593 594 Also add in the slot for the register stack pointer we save if we 595 have a landing pad. 596 597 Unfortunately, we can't access $0..$14, from unwinder code easily, so 598 store the return address in a frame slot too. FIXME: Only for 599 non-leaf functions. FIXME: Always with a landing pad, because it's 600 hard to know whether we need the other at the time we know we need 601 the offset for one (and have to state it). It's a kludge until we 602 can express the register stack in the EH frame info. 603 604 We have to do alignment here; get_frame_size will not return a 605 multiple of STACK_BOUNDARY. FIXME: Add note in manual. */ 606 607 for (regno = MMIX_FIRST_GLOBAL_REGNUM; 608 regno <= 255; 609 regno++) 610 if ((df_regs_ever_live_p (regno) && ! call_used_regs[regno]) 611 || IS_MMIX_EH_RETURN_DATA_REG (regno)) 612 fp_sp_offset += 8; 613 614 return fp_sp_offset 615 + (MMIX_CFUN_HAS_LANDING_PAD 616 ? 16 : (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS ? 8 : 0)) 617 + (fromreg == MMIX_ARG_POINTER_REGNUM ? 0 : 8); 618} 619 620static void 621mmix_function_arg_advance (cumulative_args_t argsp_v, machine_mode mode, 622 const_tree type, bool named ATTRIBUTE_UNUSED) 623{ 624 CUMULATIVE_ARGS *argsp = get_cumulative_args (argsp_v); 625 int arg_size = MMIX_FUNCTION_ARG_SIZE (mode, type); 626 627 argsp->regs = ((targetm.calls.must_pass_in_stack (mode, type) 628 || (arg_size > 8 629 && !TARGET_LIBFUNC 630 && !argsp->lib)) 631 ? (MMIX_MAX_ARGS_IN_REGS) + 1 632 : argsp->regs + (7 + arg_size) / 8); 633} 634 635/* Helper function for mmix_function_arg and mmix_function_incoming_arg. */ 636 637static rtx 638mmix_function_arg_1 (const cumulative_args_t argsp_v, 639 machine_mode mode, 640 const_tree type, 641 bool named ATTRIBUTE_UNUSED, 642 bool incoming) 643{ 644 CUMULATIVE_ARGS *argsp = get_cumulative_args (argsp_v); 645 646 /* Last-argument marker. */ 647 if (type == void_type_node) 648 return (argsp->regs < MMIX_MAX_ARGS_IN_REGS) 649 ? gen_rtx_REG (mode, 650 (incoming 651 ? MMIX_FIRST_INCOMING_ARG_REGNUM 652 : MMIX_FIRST_ARG_REGNUM) + argsp->regs) 653 : NULL_RTX; 654 655 return (argsp->regs < MMIX_MAX_ARGS_IN_REGS 656 && !targetm.calls.must_pass_in_stack (mode, type) 657 && (GET_MODE_BITSIZE (mode) <= 64 658 || argsp->lib 659 || TARGET_LIBFUNC)) 660 ? gen_rtx_REG (mode, 661 (incoming 662 ? MMIX_FIRST_INCOMING_ARG_REGNUM 663 : MMIX_FIRST_ARG_REGNUM) 664 + argsp->regs) 665 : NULL_RTX; 666} 667 668/* Return an rtx for a function argument to go in a register, and 0 for 669 one that must go on stack. */ 670 671static rtx 672mmix_function_arg (cumulative_args_t argsp, 673 machine_mode mode, 674 const_tree type, 675 bool named) 676{ 677 return mmix_function_arg_1 (argsp, mode, type, named, false); 678} 679 680static rtx 681mmix_function_incoming_arg (cumulative_args_t argsp, 682 machine_mode mode, 683 const_tree type, 684 bool named) 685{ 686 return mmix_function_arg_1 (argsp, mode, type, named, true); 687} 688 689/* Returns nonzero for everything that goes by reference, 0 for 690 everything that goes by value. */ 691 692static bool 693mmix_pass_by_reference (cumulative_args_t argsp_v, machine_mode mode, 694 const_tree type, bool named ATTRIBUTE_UNUSED) 695{ 696 CUMULATIVE_ARGS *argsp = get_cumulative_args (argsp_v); 697 698 /* FIXME: Check: I'm not sure the must_pass_in_stack check is 699 necessary. */ 700 if (targetm.calls.must_pass_in_stack (mode, type)) 701 return true; 702 703 if (MMIX_FUNCTION_ARG_SIZE (mode, type) > 8 704 && !TARGET_LIBFUNC 705 && (!argsp || !argsp->lib)) 706 return true; 707 708 return false; 709} 710 711/* Return nonzero if regno is a register number where a parameter is 712 passed, and 0 otherwise. */ 713 714int 715mmix_function_arg_regno_p (int regno, int incoming) 716{ 717 int first_arg_regnum 718 = incoming ? MMIX_FIRST_INCOMING_ARG_REGNUM : MMIX_FIRST_ARG_REGNUM; 719 720 return regno >= first_arg_regnum 721 && regno < first_arg_regnum + MMIX_MAX_ARGS_IN_REGS; 722} 723 724/* Implements TARGET_FUNCTION_VALUE. */ 725 726static rtx 727mmix_function_value (const_tree valtype, 728 const_tree func ATTRIBUTE_UNUSED, 729 bool outgoing) 730{ 731 machine_mode mode = TYPE_MODE (valtype); 732 machine_mode cmode; 733 int first_val_regnum = MMIX_OUTGOING_RETURN_VALUE_REGNUM; 734 rtx vec[MMIX_MAX_REGS_FOR_VALUE]; 735 int i; 736 int nregs; 737 738 if (!outgoing) 739 return gen_rtx_REG (mode, MMIX_RETURN_VALUE_REGNUM); 740 741 /* Return values that fit in a register need no special handling. 742 There's no register hole when parameters are passed in global 743 registers. */ 744 if (TARGET_ABI_GNU 745 || GET_MODE_BITSIZE (mode) <= BITS_PER_WORD) 746 return 747 gen_rtx_REG (mode, MMIX_OUTGOING_RETURN_VALUE_REGNUM); 748 749 if (COMPLEX_MODE_P (mode)) 750 /* A complex type, made up of components. */ 751 cmode = TYPE_MODE (TREE_TYPE (valtype)); 752 else 753 { 754 /* Of the other larger-than-register modes, we only support 755 scalar mode TImode. (At least, that's the only one that's 756 been rudimentally tested.) Make sure we're alerted for 757 unexpected cases. */ 758 if (mode != TImode) 759 sorry ("support for mode %qs", GET_MODE_NAME (mode)); 760 761 /* In any case, we will fill registers to the natural size. */ 762 cmode = DImode; 763 } 764 765 nregs = ((GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD); 766 767 /* We need to take care of the effect of the register hole on return 768 values of large sizes; the last register will appear as the first 769 register, with the rest shifted. (For complex modes, this is just 770 swapped registers.) */ 771 772 if (nregs > MMIX_MAX_REGS_FOR_VALUE) 773 internal_error ("too large function value type, needs %d registers,\ 774 have only %d registers for this", nregs, MMIX_MAX_REGS_FOR_VALUE); 775 776 /* FIXME: Maybe we should handle structure values like this too 777 (adjusted for BLKmode), perhaps for both ABI:s. */ 778 for (i = 0; i < nregs - 1; i++) 779 vec[i] 780 = gen_rtx_EXPR_LIST (VOIDmode, 781 gen_rtx_REG (cmode, first_val_regnum + i), 782 GEN_INT ((i + 1) * BITS_PER_UNIT)); 783 784 vec[nregs - 1] 785 = gen_rtx_EXPR_LIST (VOIDmode, 786 gen_rtx_REG (cmode, first_val_regnum + nregs - 1), 787 const0_rtx); 788 789 return gen_rtx_PARALLEL (mode, gen_rtvec_v (nregs, vec)); 790} 791 792/* Implements TARGET_LIBCALL_VALUE. */ 793 794static rtx 795mmix_libcall_value (machine_mode mode, 796 const_rtx fun ATTRIBUTE_UNUSED) 797{ 798 return gen_rtx_REG (mode, MMIX_RETURN_VALUE_REGNUM); 799} 800 801/* Implements TARGET_FUNCTION_VALUE_REGNO_P. */ 802 803static bool 804mmix_function_value_regno_p (const unsigned int regno) 805{ 806 return regno == MMIX_RETURN_VALUE_REGNUM; 807} 808 809/* EH_RETURN_DATA_REGNO. */ 810 811int 812mmix_eh_return_data_regno (int n) 813{ 814 if (n >= 0 && n < 4) 815 return MMIX_EH_RETURN_DATA_REGNO_START + n; 816 817 return INVALID_REGNUM; 818} 819 820/* EH_RETURN_STACKADJ_RTX. */ 821 822rtx 823mmix_eh_return_stackadj_rtx (void) 824{ 825 return gen_rtx_REG (Pmode, MMIX_EH_RETURN_STACKADJ_REGNUM); 826} 827 828/* EH_RETURN_HANDLER_RTX. */ 829 830rtx 831mmix_eh_return_handler_rtx (void) 832{ 833 return gen_rtx_REG (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM); 834} 835 836/* ASM_PREFERRED_EH_DATA_FORMAT. */ 837 838int 839mmix_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, 840 int global ATTRIBUTE_UNUSED) 841{ 842 /* This is the default (was at 2001-07-20). Revisit when needed. */ 843 return DW_EH_PE_absptr; 844} 845 846/* Make a note that we've seen the beginning of the prologue. This 847 matters to whether we'll translate register numbers as calculated by 848 mmix_reorg. */ 849 850static void 851mmix_target_asm_function_prologue (FILE *) 852{ 853 cfun->machine->in_prologue = 1; 854} 855 856/* Make a note that we've seen the end of the prologue. */ 857 858static void 859mmix_target_asm_function_end_prologue (FILE *stream ATTRIBUTE_UNUSED) 860{ 861 cfun->machine->in_prologue = 0; 862} 863 864/* Implement TARGET_MACHINE_DEPENDENT_REORG. No actual rearrangements 865 done here; just virtually by calculating the highest saved stack 866 register number used to modify the register numbers at output time. */ 867 868static void 869mmix_reorg (void) 870{ 871 int regno; 872 873 /* We put the number of the highest saved register-file register in a 874 location convenient for the call-patterns to output. Note that we 875 don't tell dwarf2 about these registers, since it can't restore them 876 anyway. */ 877 for (regno = MMIX_LAST_STACK_REGISTER_REGNUM; 878 regno >= 0; 879 regno--) 880 if ((df_regs_ever_live_p (regno) && !call_used_regs[regno]) 881 || (regno == MMIX_FRAME_POINTER_REGNUM && frame_pointer_needed)) 882 break; 883 884 /* Regardless of whether they're saved (they might be just read), we 885 mustn't include registers that carry parameters. We could scan the 886 insns to see whether they're actually used (and indeed do other less 887 trivial register usage analysis and transformations), but it seems 888 wasteful to optimize for unused parameter registers. As of 889 2002-04-30, df_regs_ever_live_p (n) seems to be set for only-reads too, but 890 that might change. */ 891 if (!TARGET_ABI_GNU && regno < crtl->args.info.regs - 1) 892 { 893 regno = crtl->args.info.regs - 1; 894 895 /* We don't want to let this cause us to go over the limit and make 896 incoming parameter registers be misnumbered and treating the last 897 parameter register and incoming return value register call-saved. 898 Stop things at the unmodified scheme. */ 899 if (regno > MMIX_RETURN_VALUE_REGNUM - 1) 900 regno = MMIX_RETURN_VALUE_REGNUM - 1; 901 } 902 903 cfun->machine->highest_saved_stack_register = regno; 904} 905 906/* TARGET_ASM_FUNCTION_EPILOGUE. */ 907 908static void 909mmix_target_asm_function_epilogue (FILE *stream) 910{ 911 /* Emit an \n for readability of the generated assembly. */ 912 fputc ('\n', stream); 913} 914 915/* TARGET_ASM_OUTPUT_MI_THUNK. */ 916 917static void 918mmix_asm_output_mi_thunk (FILE *stream, 919 tree fndecl ATTRIBUTE_UNUSED, 920 HOST_WIDE_INT delta, 921 HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED, 922 tree func) 923{ 924 /* If you define TARGET_STRUCT_VALUE_RTX that returns 0 (i.e. pass 925 location of structure to return as invisible first argument), you 926 need to tweak this code too. */ 927 const char *regname = reg_names[MMIX_FIRST_INCOMING_ARG_REGNUM]; 928 929 if (delta >= 0 && delta < 65536) 930 fprintf (stream, "\tINCL %s,%d\n", regname, (int)delta); 931 else if (delta < 0 && delta >= -255) 932 fprintf (stream, "\tSUBU %s,%s,%d\n", regname, regname, (int)-delta); 933 else 934 { 935 mmix_output_register_setting (stream, 255, delta, 1); 936 fprintf (stream, "\tADDU %s,%s,$255\n", regname, regname); 937 } 938 939 fprintf (stream, "\tJMP "); 940 assemble_name (stream, XSTR (XEXP (DECL_RTL (func), 0), 0)); 941 fprintf (stream, "\n"); 942} 943 944/* FUNCTION_PROFILER. */ 945 946void 947mmix_function_profiler (FILE *stream ATTRIBUTE_UNUSED, 948 int labelno ATTRIBUTE_UNUSED) 949{ 950 sorry ("function_profiler support for MMIX"); 951} 952 953/* Worker function for TARGET_SETUP_INCOMING_VARARGS. For the moment, 954 let's stick to pushing argument registers on the stack. Later, we 955 can parse all arguments in registers, to improve performance. */ 956 957static void 958mmix_setup_incoming_varargs (cumulative_args_t args_so_farp_v, 959 machine_mode mode, 960 tree vartype, 961 int *pretend_sizep, 962 int second_time ATTRIBUTE_UNUSED) 963{ 964 CUMULATIVE_ARGS *args_so_farp = get_cumulative_args (args_so_farp_v); 965 966 /* The last named variable has been handled, but 967 args_so_farp has not been advanced for it. */ 968 if (args_so_farp->regs + 1 < MMIX_MAX_ARGS_IN_REGS) 969 *pretend_sizep = (MMIX_MAX_ARGS_IN_REGS - (args_so_farp->regs + 1)) * 8; 970 971 /* We assume that one argument takes up one register here. That should 972 be true until we start messing with multi-reg parameters. */ 973 if ((7 + (MMIX_FUNCTION_ARG_SIZE (mode, vartype))) / 8 != 1) 974 internal_error ("MMIX Internal: Last named vararg would not fit in a register"); 975} 976 977/* TARGET_ASM_TRAMPOLINE_TEMPLATE. */ 978 979static void 980mmix_asm_trampoline_template (FILE *stream) 981{ 982 /* Read a value into the static-chain register and jump somewhere. The 983 static chain is stored at offset 16, and the function address is 984 stored at offset 24. */ 985 986 fprintf (stream, "\tGETA $255,1F\n\t"); 987 fprintf (stream, "LDOU %s,$255,0\n\t", reg_names[MMIX_STATIC_CHAIN_REGNUM]); 988 fprintf (stream, "LDOU $255,$255,8\n\t"); 989 fprintf (stream, "GO $255,$255,0\n"); 990 fprintf (stream, "1H\tOCTA 0\n\t"); 991 fprintf (stream, "OCTA 0\n"); 992} 993 994/* TARGET_TRAMPOLINE_INIT. */ 995/* Set the static chain and function pointer field in the trampoline. 996 We also SYNCID here to be sure (doesn't matter in the simulator, but 997 some day it will). */ 998 999static void 1000mmix_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain) 1001{ 1002 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); 1003 rtx mem; 1004 1005 emit_block_move (m_tramp, assemble_trampoline_template (), 1006 GEN_INT (2*UNITS_PER_WORD), BLOCK_OP_NORMAL); 1007 1008 mem = adjust_address (m_tramp, DImode, 2*UNITS_PER_WORD); 1009 emit_move_insn (mem, static_chain); 1010 mem = adjust_address (m_tramp, DImode, 3*UNITS_PER_WORD); 1011 emit_move_insn (mem, fnaddr); 1012 1013 mem = adjust_address (m_tramp, DImode, 0); 1014 emit_insn (gen_sync_icache (mem, GEN_INT (TRAMPOLINE_SIZE - 1))); 1015} 1016 1017/* We must exclude constant addresses that have an increment that is not a 1018 multiple of four bytes because of restrictions of the GETA 1019 instruction, unless TARGET_BASE_ADDRESSES. */ 1020 1021int 1022mmix_constant_address_p (rtx x) 1023{ 1024 RTX_CODE code = GET_CODE (x); 1025 int addend = 0; 1026 /* When using "base addresses", anything constant goes. */ 1027 int constant_ok = TARGET_BASE_ADDRESSES != 0; 1028 1029 switch (code) 1030 { 1031 case LABEL_REF: 1032 case SYMBOL_REF: 1033 return 1; 1034 1035 case HIGH: 1036 /* FIXME: Don't know how to dissect these. Avoid them for now, 1037 except we know they're constants. */ 1038 return constant_ok; 1039 1040 case CONST_INT: 1041 addend = INTVAL (x); 1042 break; 1043 1044 case CONST_DOUBLE: 1045 if (GET_MODE (x) != VOIDmode) 1046 /* Strange that we got here. FIXME: Check if we do. */ 1047 return constant_ok; 1048 addend = CONST_DOUBLE_LOW (x); 1049 break; 1050 1051 case CONST: 1052 /* Note that expressions with arithmetic on forward references don't 1053 work in mmixal. People using gcc assembly code with mmixal might 1054 need to move arrays and such to before the point of use. */ 1055 if (GET_CODE (XEXP (x, 0)) == PLUS) 1056 { 1057 rtx x0 = XEXP (XEXP (x, 0), 0); 1058 rtx x1 = XEXP (XEXP (x, 0), 1); 1059 1060 if ((GET_CODE (x0) == SYMBOL_REF 1061 || GET_CODE (x0) == LABEL_REF) 1062 && (GET_CODE (x1) == CONST_INT 1063 || (GET_CODE (x1) == CONST_DOUBLE 1064 && GET_MODE (x1) == VOIDmode))) 1065 addend = mmix_intval (x1); 1066 else 1067 return constant_ok; 1068 } 1069 else 1070 return constant_ok; 1071 break; 1072 1073 default: 1074 return 0; 1075 } 1076 1077 return constant_ok || (addend & 3) == 0; 1078} 1079 1080/* Return 1 if the address is OK, otherwise 0. */ 1081 1082bool 1083mmix_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, 1084 rtx x, 1085 bool strict_checking) 1086{ 1087#define MMIX_REG_OK(X) \ 1088 ((strict_checking \ 1089 && (REGNO (X) <= MMIX_LAST_GENERAL_REGISTER \ 1090 || (reg_renumber[REGNO (X)] > 0 \ 1091 && reg_renumber[REGNO (X)] <= MMIX_LAST_GENERAL_REGISTER))) \ 1092 || (!strict_checking \ 1093 && (REGNO (X) <= MMIX_LAST_GENERAL_REGISTER \ 1094 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ 1095 || REGNO (X) == ARG_POINTER_REGNUM))) 1096 1097 /* We only accept: 1098 (mem reg) 1099 (mem (plus reg reg)) 1100 (mem (plus reg 0..255)). 1101 unless TARGET_BASE_ADDRESSES, in which case we accept all 1102 (mem constant_address) too. */ 1103 1104 1105 /* (mem reg) */ 1106 if (REG_P (x) && MMIX_REG_OK (x)) 1107 return 1; 1108 1109 if (GET_CODE(x) == PLUS) 1110 { 1111 rtx x1 = XEXP (x, 0); 1112 rtx x2 = XEXP (x, 1); 1113 1114 /* Try swapping the order. FIXME: Do we need this? */ 1115 if (! REG_P (x1)) 1116 { 1117 rtx tem = x1; 1118 x1 = x2; 1119 x2 = tem; 1120 } 1121 1122 /* (mem (plus (reg?) (?))) */ 1123 if (!REG_P (x1) || !MMIX_REG_OK (x1)) 1124 return TARGET_BASE_ADDRESSES && mmix_constant_address_p (x); 1125 1126 /* (mem (plus (reg) (reg?))) */ 1127 if (REG_P (x2) && MMIX_REG_OK (x2)) 1128 return 1; 1129 1130 /* (mem (plus (reg) (0..255?))) */ 1131 if (satisfies_constraint_I (x2)) 1132 return 1; 1133 1134 return 0; 1135 } 1136 1137 return TARGET_BASE_ADDRESSES && mmix_constant_address_p (x); 1138} 1139 1140/* Implement TARGET_LEGITIMATE_CONSTANT_P. */ 1141 1142static bool 1143mmix_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x) 1144{ 1145 RTX_CODE code = GET_CODE (x); 1146 1147 /* We must allow any number due to the way the cse passes works; if we 1148 do not allow any number here, general_operand will fail, and insns 1149 will fatally fail recognition instead of "softly". */ 1150 if (code == CONST_INT || code == CONST_DOUBLE) 1151 return 1; 1152 1153 return CONSTANT_ADDRESS_P (x); 1154} 1155 1156/* SELECT_CC_MODE. */ 1157 1158machine_mode 1159mmix_select_cc_mode (RTX_CODE op, rtx x, rtx y ATTRIBUTE_UNUSED) 1160{ 1161 /* We use CCmode, CC_UNSmode, CC_FPmode, CC_FPEQmode and CC_FUNmode to 1162 output different compare insns. Note that we do not check the 1163 validity of the comparison here. */ 1164 1165 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) 1166 { 1167 if (op == ORDERED || op == UNORDERED || op == UNGE 1168 || op == UNGT || op == UNLE || op == UNLT) 1169 return CC_FUNmode; 1170 1171 if (op == EQ || op == NE) 1172 return CC_FPEQmode; 1173 1174 return CC_FPmode; 1175 } 1176 1177 if (op == GTU || op == LTU || op == GEU || op == LEU) 1178 return CC_UNSmode; 1179 1180 return CCmode; 1181} 1182 1183/* REVERSIBLE_CC_MODE. */ 1184 1185int 1186mmix_reversible_cc_mode (machine_mode mode) 1187{ 1188 /* That is, all integer and the EQ, NE, ORDERED and UNORDERED float 1189 compares. */ 1190 return mode != CC_FPmode; 1191} 1192 1193/* TARGET_RTX_COSTS. */ 1194 1195static bool 1196mmix_rtx_costs (rtx x ATTRIBUTE_UNUSED, 1197 machine_mode mode ATTRIBUTE_UNUSED, 1198 int outer_code ATTRIBUTE_UNUSED, 1199 int opno ATTRIBUTE_UNUSED, 1200 int *total ATTRIBUTE_UNUSED, 1201 bool speed ATTRIBUTE_UNUSED) 1202{ 1203 /* For the time being, this is just a stub and we'll accept the 1204 generic calculations, until we can do measurements, at least. 1205 Say we did not modify any calculated costs. */ 1206 return false; 1207} 1208 1209/* TARGET_REGISTER_MOVE_COST. 1210 1211 The special registers can only move to and from general regs, and we 1212 need to check that their constraints match, so say 3 for them. */ 1213 1214static int 1215mmix_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, 1216 reg_class_t from, 1217 reg_class_t to) 1218{ 1219 return (from == GENERAL_REGS && from == to) ? 2 : 3; 1220} 1221 1222/* Note that we don't have a TEXT_SECTION_ASM_OP, because it has to be a 1223 compile-time constant; it's used in an asm in crtstuff.c, compiled for 1224 the target. */ 1225 1226/* DATA_SECTION_ASM_OP. */ 1227 1228const char * 1229mmix_data_section_asm_op (void) 1230{ 1231 return "\t.data ! mmixal:= 8H LOC 9B"; 1232} 1233 1234static void 1235mmix_encode_section_info (tree decl, rtx rtl, int first) 1236{ 1237 /* Test for an external declaration, and do nothing if it is one. */ 1238 if ((TREE_CODE (decl) == VAR_DECL 1239 && (DECL_EXTERNAL (decl) || TREE_PUBLIC (decl))) 1240 || (TREE_CODE (decl) == FUNCTION_DECL && TREE_PUBLIC (decl))) 1241 ; 1242 else if (first && DECL_P (decl)) 1243 { 1244 /* For non-visible declarations, add a "@" prefix, which we skip 1245 when the label is output. If the label does not have this 1246 prefix, a ":" is output if -mtoplevel-symbols. 1247 1248 Note that this does not work for data that is declared extern and 1249 later defined as static. If there's code in between, that code 1250 will refer to the extern declaration, and vice versa. This just 1251 means that when -mtoplevel-symbols is in use, we can just handle 1252 well-behaved ISO-compliant code. */ 1253 1254 const char *str = XSTR (XEXP (rtl, 0), 0); 1255 int len = strlen (str); 1256 char *newstr = XALLOCAVEC (char, len + 2); 1257 newstr[0] = '@'; 1258 strcpy (newstr + 1, str); 1259 XSTR (XEXP (rtl, 0), 0) = ggc_alloc_string (newstr, len + 1); 1260 } 1261 1262 /* Set SYMBOL_REF_FLAG for things that we want to access with GETA. We 1263 may need different options to reach for different things with GETA. 1264 For now, functions and things we know or have been told are constant. */ 1265 if (TREE_CODE (decl) == FUNCTION_DECL 1266 || TREE_CONSTANT (decl) 1267 || (TREE_CODE (decl) == VAR_DECL 1268 && TREE_READONLY (decl) 1269 && !TREE_SIDE_EFFECTS (decl) 1270 && (!DECL_INITIAL (decl) 1271 || TREE_CONSTANT (DECL_INITIAL (decl))))) 1272 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; 1273} 1274 1275static const char * 1276mmix_strip_name_encoding (const char *name) 1277{ 1278 for (; (*name == '@' || *name == '*'); name++) 1279 ; 1280 1281 return name; 1282} 1283 1284/* TARGET_ASM_FILE_START. 1285 We just emit a little comment for the time being. */ 1286 1287static void 1288mmix_file_start (void) 1289{ 1290 default_file_start (); 1291 1292 fputs ("! mmixal:= 8H LOC Data_Section\n", asm_out_file); 1293 1294 /* Make sure each file starts with the text section. */ 1295 switch_to_section (text_section); 1296} 1297 1298/* TARGET_ASM_FILE_END. */ 1299 1300static void 1301mmix_file_end (void) 1302{ 1303 /* Make sure each file ends with the data section. */ 1304 switch_to_section (data_section); 1305} 1306 1307/* TARGET_ASM_OUTPUT_SOURCE_FILENAME. */ 1308 1309static void 1310mmix_asm_output_source_filename (FILE *stream, const char *name) 1311{ 1312 fprintf (stream, "# 1 "); 1313 OUTPUT_QUOTED_STRING (stream, name); 1314 fprintf (stream, "\n"); 1315} 1316 1317/* Unfortunately, by default __builtin_ffs is expanded to ffs for 1318 targets where INT_TYPE_SIZE < BITS_PER_WORD. That together with 1319 newlib since 2017-07-04 implementing ffs as __builtin_ffs leads to 1320 (newlib) ffs recursively calling itself. But, because of argument 1321 promotion, and with ffs we're counting from the least bit, the 1322 libgcc equivalent for ffsl works equally well for int arguments, so 1323 just use that. */ 1324 1325static void 1326mmix_init_libfuncs (void) 1327{ 1328 set_optab_libfunc (ffs_optab, SImode, "__ffsdi2"); 1329} 1330 1331/* OUTPUT_QUOTED_STRING. */ 1332 1333void 1334mmix_output_quoted_string (FILE *stream, const char *string, int length) 1335{ 1336 const char * string_end = string + length; 1337 static const char *const unwanted_chars = "\"[]\\"; 1338 1339 /* Output "any character except newline and double quote character". We 1340 play it safe and avoid all control characters too. We also do not 1341 want [] as characters, should input be passed through m4 with [] as 1342 quotes. Further, we avoid "\", because the GAS port handles it as a 1343 quoting character. */ 1344 while (string < string_end) 1345 { 1346 if (*string 1347 && (unsigned char) *string < 128 1348 && !ISCNTRL (*string) 1349 && strchr (unwanted_chars, *string) == NULL) 1350 { 1351 fputc ('"', stream); 1352 while (*string 1353 && (unsigned char) *string < 128 1354 && !ISCNTRL (*string) 1355 && strchr (unwanted_chars, *string) == NULL 1356 && string < string_end) 1357 { 1358 fputc (*string, stream); 1359 string++; 1360 } 1361 fputc ('"', stream); 1362 if (string < string_end) 1363 fprintf (stream, ","); 1364 } 1365 if (string < string_end) 1366 { 1367 fprintf (stream, "#%x", *string & 255); 1368 string++; 1369 if (string < string_end) 1370 fprintf (stream, ","); 1371 } 1372 } 1373} 1374 1375/* Target hook for assembling integer objects. Use mmix_print_operand 1376 for WYDE and TETRA. Use mmix_output_octa to output 8-byte 1377 CONST_DOUBLEs. */ 1378 1379static bool 1380mmix_assemble_integer (rtx x, unsigned int size, int aligned_p) 1381{ 1382 if (aligned_p) 1383 switch (size) 1384 { 1385 /* We handle a limited number of types of operands in here. But 1386 that's ok, because we can punt to generic functions. We then 1387 pretend that aligned data isn't needed, so the usual .<pseudo> 1388 syntax is used (which works for aligned data too). We actually 1389 *must* do that, since we say we don't have simple aligned 1390 pseudos, causing this function to be called. We just try and 1391 keep as much compatibility as possible with mmixal syntax for 1392 normal cases (i.e. without GNU extensions and C only). */ 1393 case 1: 1394 if (GET_CODE (x) != CONST_INT) 1395 { 1396 /* There is no "unaligned byte" op or generic function to 1397 which we can punt, so we have to handle this here. As 1398 the expression isn't a plain literal, the generated 1399 assembly-code can't be mmixal-equivalent (i.e. "BYTE" 1400 won't work) and thus it's ok to emit the default op 1401 ".byte". */ 1402 assemble_integer_with_op ("\t.byte\t", x); 1403 return true; 1404 } 1405 fputs ("\tBYTE\t", asm_out_file); 1406 mmix_print_operand (asm_out_file, x, 'B'); 1407 fputc ('\n', asm_out_file); 1408 return true; 1409 1410 case 2: 1411 if (GET_CODE (x) != CONST_INT) 1412 { 1413 aligned_p = 0; 1414 break; 1415 } 1416 fputs ("\tWYDE\t", asm_out_file); 1417 mmix_print_operand (asm_out_file, x, 'W'); 1418 fputc ('\n', asm_out_file); 1419 return true; 1420 1421 case 4: 1422 if (GET_CODE (x) != CONST_INT) 1423 { 1424 aligned_p = 0; 1425 break; 1426 } 1427 fputs ("\tTETRA\t", asm_out_file); 1428 mmix_print_operand (asm_out_file, x, 'L'); 1429 fputc ('\n', asm_out_file); 1430 return true; 1431 1432 case 8: 1433 /* We don't get here anymore for CONST_DOUBLE, because DImode 1434 isn't expressed as CONST_DOUBLE, and DFmode is handled 1435 elsewhere. */ 1436 gcc_assert (GET_CODE (x) != CONST_DOUBLE); 1437 assemble_integer_with_op ("\tOCTA\t", x); 1438 return true; 1439 } 1440 return default_assemble_integer (x, size, aligned_p); 1441} 1442 1443/* ASM_OUTPUT_ASCII. */ 1444 1445void 1446mmix_asm_output_ascii (FILE *stream, const char *string, int length) 1447{ 1448 while (length > 0) 1449 { 1450 int chunk_size = length > 60 ? 60 : length; 1451 fprintf (stream, "\tBYTE "); 1452 mmix_output_quoted_string (stream, string, chunk_size); 1453 string += chunk_size; 1454 length -= chunk_size; 1455 fprintf (stream, "\n"); 1456 } 1457} 1458 1459/* ASM_OUTPUT_ALIGNED_COMMON. */ 1460 1461void 1462mmix_asm_output_aligned_common (FILE *stream, 1463 const char *name, 1464 int size, 1465 int align) 1466{ 1467 /* This is mostly the elfos.h one. There doesn't seem to be a way to 1468 express this in a mmixal-compatible way. */ 1469 fprintf (stream, "\t.comm\t"); 1470 assemble_name (stream, name); 1471 fprintf (stream, ",%u,%u ! mmixal-incompatible COMMON\n", 1472 size, align / BITS_PER_UNIT); 1473} 1474 1475/* ASM_OUTPUT_ALIGNED_LOCAL. */ 1476 1477void 1478mmix_asm_output_aligned_local (FILE *stream, 1479 const char *name, 1480 int size, 1481 int align) 1482{ 1483 switch_to_section (data_section); 1484 1485 ASM_OUTPUT_ALIGN (stream, exact_log2 (align/BITS_PER_UNIT)); 1486 assemble_name (stream, name); 1487 fprintf (stream, "\tLOC @+%d\n", size); 1488} 1489 1490/* ASM_OUTPUT_LABEL. */ 1491 1492void 1493mmix_asm_output_label (FILE *stream, const char *name) 1494{ 1495 assemble_name (stream, name); 1496 fprintf (stream, "\tIS @\n"); 1497} 1498 1499/* ASM_OUTPUT_INTERNAL_LABEL. */ 1500 1501void 1502mmix_asm_output_internal_label (FILE *stream, const char *name) 1503{ 1504 assemble_name_raw (stream, name); 1505 fprintf (stream, "\tIS @\n"); 1506} 1507 1508/* ASM_DECLARE_REGISTER_GLOBAL. */ 1509 1510void 1511mmix_asm_declare_register_global (FILE *stream ATTRIBUTE_UNUSED, 1512 tree decl ATTRIBUTE_UNUSED, 1513 int regno ATTRIBUTE_UNUSED, 1514 const char *name ATTRIBUTE_UNUSED) 1515{ 1516 /* Nothing to do here, but there *will* be, therefore the framework is 1517 here. */ 1518} 1519 1520/* ASM_WEAKEN_LABEL. */ 1521 1522void 1523mmix_asm_weaken_label (FILE *stream ATTRIBUTE_UNUSED, 1524 const char *name ATTRIBUTE_UNUSED) 1525{ 1526 fprintf (stream, "\t.weak "); 1527 assemble_name (stream, name); 1528 fprintf (stream, " ! mmixal-incompatible\n"); 1529} 1530 1531/* MAKE_DECL_ONE_ONLY. */ 1532 1533void 1534mmix_make_decl_one_only (tree decl) 1535{ 1536 DECL_WEAK (decl) = 1; 1537} 1538 1539/* ASM_OUTPUT_LABELREF. 1540 Strip GCC's '*' and our own '@'. No order is assumed. */ 1541 1542void 1543mmix_asm_output_labelref (FILE *stream, const char *name) 1544{ 1545 int is_extern = 1; 1546 1547 for (; (*name == '@' || *name == '*'); name++) 1548 if (*name == '@') 1549 is_extern = 0; 1550 1551 asm_fprintf (stream, "%s%U%s", 1552 is_extern && TARGET_TOPLEVEL_SYMBOLS ? ":" : "", 1553 name); 1554} 1555 1556/* ASM_OUTPUT_DEF. */ 1557 1558void 1559mmix_asm_output_def (FILE *stream, const char *name, const char *value) 1560{ 1561 assemble_name (stream, name); 1562 fprintf (stream, "\tIS "); 1563 assemble_name (stream, value); 1564 fputc ('\n', stream); 1565} 1566 1567/* TARGET_PRINT_OPERAND. */ 1568 1569static void 1570mmix_print_operand (FILE *stream, rtx x, int code) 1571{ 1572 /* When we add support for different codes later, we can, when needed, 1573 drop through to the main handler with a modified operand. */ 1574 rtx modified_x = x; 1575 int regno = x != NULL_RTX && REG_P (x) ? REGNO (x) : 0; 1576 1577 switch (code) 1578 { 1579 /* Unrelated codes are in alphabetic order. */ 1580 1581 case '+': 1582 /* For conditional branches, output "P" for a probable branch. */ 1583 if (TARGET_BRANCH_PREDICT) 1584 { 1585 x = find_reg_note (current_output_insn, REG_BR_PROB, 0); 1586 if (x && profile_probability::from_reg_br_prob_note (XINT (x, 0)) 1587 > profile_probability::even ()) 1588 putc ('P', stream); 1589 } 1590 return; 1591 1592 case '.': 1593 /* For the %d in POP %d,0. */ 1594 fprintf (stream, "%d", MMIX_POP_ARGUMENT ()); 1595 return; 1596 1597 case 'B': 1598 if (GET_CODE (x) != CONST_INT) 1599 fatal_insn ("MMIX Internal: Expected a CONST_INT, not this", x); 1600 fprintf (stream, "%d", (int) (INTVAL (x) & 0xff)); 1601 return; 1602 1603 case 'H': 1604 /* Highpart. Must be general register, and not the last one, as 1605 that one cannot be part of a consecutive register pair. */ 1606 if (regno > MMIX_LAST_GENERAL_REGISTER - 1) 1607 internal_error ("MMIX Internal: Bad register: %d", regno); 1608 1609 /* This is big-endian, so the high-part is the first one. */ 1610 fprintf (stream, "%s", reg_names[MMIX_OUTPUT_REGNO (regno)]); 1611 return; 1612 1613 case 'L': 1614 /* Lowpart. Must be CONST_INT or general register, and not the last 1615 one, as that one cannot be part of a consecutive register pair. */ 1616 if (GET_CODE (x) == CONST_INT) 1617 { 1618 fprintf (stream, "#%lx", 1619 (unsigned long) (INTVAL (x) 1620 & ((unsigned int) 0x7fffffff * 2 + 1))); 1621 return; 1622 } 1623 1624 if (GET_CODE (x) == SYMBOL_REF) 1625 { 1626 output_addr_const (stream, x); 1627 return; 1628 } 1629 1630 if (regno > MMIX_LAST_GENERAL_REGISTER - 1) 1631 internal_error ("MMIX Internal: Bad register: %d", regno); 1632 1633 /* This is big-endian, so the low-part is + 1. */ 1634 fprintf (stream, "%s", reg_names[MMIX_OUTPUT_REGNO (regno) + 1]); 1635 return; 1636 1637 /* Can't use 'a' because that's a generic modifier for address 1638 output. */ 1639 case 'A': 1640 mmix_output_shiftvalue_op_from_str (stream, "ANDN", 1641 ~(uint64_t) 1642 mmix_intval (x)); 1643 return; 1644 1645 case 'i': 1646 mmix_output_shiftvalue_op_from_str (stream, "INC", 1647 (uint64_t) 1648 mmix_intval (x)); 1649 return; 1650 1651 case 'o': 1652 mmix_output_shiftvalue_op_from_str (stream, "OR", 1653 (uint64_t) 1654 mmix_intval (x)); 1655 return; 1656 1657 case 's': 1658 mmix_output_shiftvalue_op_from_str (stream, "SET", 1659 (uint64_t) 1660 mmix_intval (x)); 1661 return; 1662 1663 case 'd': 1664 case 'D': 1665 mmix_output_condition (stream, x, (code == 'D')); 1666 return; 1667 1668 case 'e': 1669 /* Output an extra "e" to make fcmpe, fune. */ 1670 if (TARGET_FCMP_EPSILON) 1671 fprintf (stream, "e"); 1672 return; 1673 1674 case 'm': 1675 /* Output the number minus 1. */ 1676 if (GET_CODE (x) != CONST_INT) 1677 { 1678 fatal_insn ("MMIX Internal: Bad value for 'm', not a CONST_INT", 1679 x); 1680 } 1681 fprintf (stream, "%" PRId64, 1682 (int64_t) (mmix_intval (x) - 1)); 1683 return; 1684 1685 case 'p': 1686 /* Store the number of registers we want to save. This was setup 1687 by the prologue. The actual operand contains the number of 1688 registers to pass, but we don't use it currently. Anyway, we 1689 need to output the number of saved registers here. */ 1690 fprintf (stream, "%d", 1691 cfun->machine->highest_saved_stack_register + 1); 1692 return; 1693 1694 case 'r': 1695 /* Store the register to output a constant to. */ 1696 if (! REG_P (x)) 1697 fatal_insn ("MMIX Internal: Expected a register, not this", x); 1698 mmix_output_destination_register = MMIX_OUTPUT_REGNO (regno); 1699 return; 1700 1701 case 'I': 1702 /* Output the constant. Note that we use this for floats as well. */ 1703 if (GET_CODE (x) != CONST_INT 1704 && (GET_CODE (x) != CONST_DOUBLE 1705 || (GET_MODE (x) != VOIDmode && GET_MODE (x) != DFmode 1706 && GET_MODE (x) != SFmode))) 1707 fatal_insn ("MMIX Internal: Expected a constant, not this", x); 1708 mmix_output_register_setting (stream, 1709 mmix_output_destination_register, 1710 mmix_intval (x), 0); 1711 return; 1712 1713 case 'U': 1714 /* An U for unsigned, if TARGET_ZERO_EXTEND. Ignore the operand. */ 1715 if (TARGET_ZERO_EXTEND) 1716 putc ('U', stream); 1717 return; 1718 1719 case 'v': 1720 mmix_output_shifted_value (stream, (int64_t) mmix_intval (x)); 1721 return; 1722 1723 case 'V': 1724 mmix_output_shifted_value (stream, (int64_t) ~mmix_intval (x)); 1725 return; 1726 1727 case 'W': 1728 if (GET_CODE (x) != CONST_INT) 1729 fatal_insn ("MMIX Internal: Expected a CONST_INT, not this", x); 1730 fprintf (stream, "#%x", (int) (INTVAL (x) & 0xffff)); 1731 return; 1732 1733 case 0: 1734 /* Nothing to do. */ 1735 break; 1736 1737 default: 1738 /* Presumably there's a missing case above if we get here. */ 1739 internal_error ("MMIX Internal: Missing %qc case in mmix_print_operand", code); 1740 } 1741 1742 switch (GET_CODE (modified_x)) 1743 { 1744 case REG: 1745 regno = REGNO (modified_x); 1746 if (regno >= FIRST_PSEUDO_REGISTER) 1747 internal_error ("MMIX Internal: Bad register: %d", regno); 1748 fprintf (stream, "%s", reg_names[MMIX_OUTPUT_REGNO (regno)]); 1749 return; 1750 1751 case MEM: 1752 output_address (GET_MODE (modified_x), XEXP (modified_x, 0)); 1753 return; 1754 1755 case CONST_INT: 1756 /* For -2147483648, mmixal complains that the constant does not fit 1757 in 4 bytes, so let's output it as hex. Take care to handle hosts 1758 where HOST_WIDE_INT is longer than an int. 1759 1760 Print small constants +-255 using decimal. */ 1761 1762 if (INTVAL (modified_x) > -256 && INTVAL (modified_x) < 256) 1763 fprintf (stream, "%d", (int) (INTVAL (modified_x))); 1764 else 1765 fprintf (stream, "#%x", 1766 (int) (INTVAL (modified_x)) & (unsigned int) ~0); 1767 return; 1768 1769 case CONST_DOUBLE: 1770 /* Do somewhat as CONST_INT. */ 1771 mmix_output_octa (stream, mmix_intval (modified_x), 0); 1772 return; 1773 1774 case CONST: 1775 output_addr_const (stream, modified_x); 1776 return; 1777 1778 default: 1779 /* No need to test for all strange things. Let output_addr_const do 1780 it for us. */ 1781 if (CONSTANT_P (modified_x) 1782 /* Strangely enough, this is not included in CONSTANT_P. 1783 FIXME: Ask/check about sanity here. */ 1784 || LABEL_P (modified_x)) 1785 { 1786 output_addr_const (stream, modified_x); 1787 return; 1788 } 1789 1790 /* We need the original here. */ 1791 fatal_insn ("MMIX Internal: Cannot decode this operand", x); 1792 } 1793} 1794 1795/* TARGET_PRINT_OPERAND_PUNCT_VALID_P. */ 1796 1797static bool 1798mmix_print_operand_punct_valid_p (unsigned char code) 1799{ 1800 /* A '+' is used for branch prediction, similar to other ports. */ 1801 return code == '+' 1802 /* A '.' is used for the %d in the POP %d,0 return insn. */ 1803 || code == '.'; 1804} 1805 1806/* TARGET_PRINT_OPERAND_ADDRESS. */ 1807 1808static void 1809mmix_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x) 1810{ 1811 if (REG_P (x)) 1812 { 1813 /* I find the generated assembly code harder to read without 1814 the ",0". */ 1815 fprintf (stream, "%s,0", reg_names[MMIX_OUTPUT_REGNO (REGNO (x))]); 1816 return; 1817 } 1818 else if (GET_CODE (x) == PLUS) 1819 { 1820 rtx x1 = XEXP (x, 0); 1821 rtx x2 = XEXP (x, 1); 1822 1823 if (REG_P (x1)) 1824 { 1825 fprintf (stream, "%s,", reg_names[MMIX_OUTPUT_REGNO (REGNO (x1))]); 1826 1827 if (REG_P (x2)) 1828 { 1829 fprintf (stream, "%s", 1830 reg_names[MMIX_OUTPUT_REGNO (REGNO (x2))]); 1831 return; 1832 } 1833 else if (satisfies_constraint_I (x2)) 1834 { 1835 output_addr_const (stream, x2); 1836 return; 1837 } 1838 } 1839 } 1840 1841 if (TARGET_BASE_ADDRESSES && mmix_legitimate_constant_p (Pmode, x)) 1842 { 1843 output_addr_const (stream, x); 1844 return; 1845 } 1846 1847 fatal_insn ("MMIX Internal: This is not a recognized address", x); 1848} 1849 1850/* ASM_OUTPUT_REG_PUSH. */ 1851 1852void 1853mmix_asm_output_reg_push (FILE *stream, int regno) 1854{ 1855 fprintf (stream, "\tSUBU %s,%s,8\n\tSTOU %s,%s,0\n", 1856 reg_names[MMIX_STACK_POINTER_REGNUM], 1857 reg_names[MMIX_STACK_POINTER_REGNUM], 1858 reg_names[MMIX_OUTPUT_REGNO (regno)], 1859 reg_names[MMIX_STACK_POINTER_REGNUM]); 1860} 1861 1862/* ASM_OUTPUT_REG_POP. */ 1863 1864void 1865mmix_asm_output_reg_pop (FILE *stream, int regno) 1866{ 1867 fprintf (stream, "\tLDOU %s,%s,0\n\tINCL %s,8\n", 1868 reg_names[MMIX_OUTPUT_REGNO (regno)], 1869 reg_names[MMIX_STACK_POINTER_REGNUM], 1870 reg_names[MMIX_STACK_POINTER_REGNUM]); 1871} 1872 1873/* ASM_OUTPUT_ADDR_DIFF_ELT. */ 1874 1875void 1876mmix_asm_output_addr_diff_elt (FILE *stream, 1877 rtx body ATTRIBUTE_UNUSED, 1878 int value, 1879 int rel) 1880{ 1881 fprintf (stream, "\tTETRA L%d-L%d\n", value, rel); 1882} 1883 1884/* ASM_OUTPUT_ADDR_VEC_ELT. */ 1885 1886void 1887mmix_asm_output_addr_vec_elt (FILE *stream, int value) 1888{ 1889 fprintf (stream, "\tOCTA L:%d\n", value); 1890} 1891 1892/* ASM_OUTPUT_SKIP. */ 1893 1894void 1895mmix_asm_output_skip (FILE *stream, int nbytes) 1896{ 1897 fprintf (stream, "\tLOC @+%d\n", nbytes); 1898} 1899 1900/* ASM_OUTPUT_ALIGN. */ 1901 1902void 1903mmix_asm_output_align (FILE *stream, int power) 1904{ 1905 /* We need to record the needed alignment of this section in the object, 1906 so we have to output an alignment directive. Use a .p2align (not 1907 .align) so people will never have to wonder about whether the 1908 argument is in number of bytes or the log2 thereof. We do it in 1909 addition to the LOC directive, so nothing needs tweaking when 1910 copy-pasting assembly into mmixal. */ 1911 fprintf (stream, "\t.p2align %d\n", power); 1912 fprintf (stream, "\tLOC @+(%d-@)&%d\n", 1 << power, (1 << power) - 1); 1913} 1914 1915/* DBX_REGISTER_NUMBER. */ 1916 1917unsigned 1918mmix_dbx_register_number (unsigned regno) 1919{ 1920 /* Adjust the register number to the one it will be output as, dammit. 1921 It'd be nice if we could check the assumption that we're filling a 1922 gap, but every register between the last saved register and parameter 1923 registers might be a valid parameter register. */ 1924 regno = MMIX_OUTPUT_REGNO (regno); 1925 1926 /* We need to renumber registers to get the number of the return address 1927 register in the range 0..255. It is also space-saving if registers 1928 mentioned in the call-frame information (which uses this function by 1929 defaulting DWARF_FRAME_REGNUM to DBX_REGISTER_NUMBER) are numbered 1930 0 .. 63. So map 224 .. 256+15 -> 0 .. 47 and 0 .. 223 -> 48..223+48. */ 1931 return regno >= 224 ? (regno - 224) : (regno + 48); 1932} 1933 1934/* End of target macro support functions. 1935 1936 Now the MMIX port's own functions. First the exported ones. */ 1937 1938/* Wrapper for get_hard_reg_initial_val since integrate.h isn't included 1939 from insn-emit.c. */ 1940 1941rtx 1942mmix_get_hard_reg_initial_val (machine_mode mode, int regno) 1943{ 1944 return get_hard_reg_initial_val (mode, regno); 1945} 1946 1947/* Nonzero when the function epilogue is simple enough that a single 1948 "POP %d,0" should be used even within the function. */ 1949 1950int 1951mmix_use_simple_return (void) 1952{ 1953 int regno; 1954 1955 int stack_space_to_allocate 1956 = (crtl->outgoing_args_size 1957 + crtl->args.pretend_args_size 1958 + get_frame_size () + 7) & ~7; 1959 1960 if (!TARGET_USE_RETURN_INSN || !reload_completed) 1961 return 0; 1962 1963 for (regno = 255; 1964 regno >= MMIX_FIRST_GLOBAL_REGNUM; 1965 regno--) 1966 /* Note that we assume that the frame-pointer-register is one of these 1967 registers, in which case we don't count it here. */ 1968 if ((((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed) 1969 && df_regs_ever_live_p (regno) && !call_used_regs[regno])) 1970 || IS_MMIX_EH_RETURN_DATA_REG (regno)) 1971 return 0; 1972 1973 if (frame_pointer_needed) 1974 stack_space_to_allocate += 8; 1975 1976 if (MMIX_CFUN_HAS_LANDING_PAD) 1977 stack_space_to_allocate += 16; 1978 else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS) 1979 stack_space_to_allocate += 8; 1980 1981 return stack_space_to_allocate == 0; 1982} 1983 1984 1985/* Expands the function prologue into RTX. */ 1986 1987void 1988mmix_expand_prologue (void) 1989{ 1990 HOST_WIDE_INT locals_size = get_frame_size (); 1991 int regno; 1992 HOST_WIDE_INT stack_space_to_allocate 1993 = (crtl->outgoing_args_size 1994 + crtl->args.pretend_args_size 1995 + locals_size + 7) & ~7; 1996 HOST_WIDE_INT offset = -8; 1997 1998 /* Add room needed to save global non-register-stack registers. */ 1999 for (regno = 255; 2000 regno >= MMIX_FIRST_GLOBAL_REGNUM; 2001 regno--) 2002 /* Note that we assume that the frame-pointer-register is one of these 2003 registers, in which case we don't count it here. */ 2004 if ((((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed) 2005 && df_regs_ever_live_p (regno) && !call_used_regs[regno])) 2006 || IS_MMIX_EH_RETURN_DATA_REG (regno)) 2007 stack_space_to_allocate += 8; 2008 2009 /* If we do have a frame-pointer, add room for it. */ 2010 if (frame_pointer_needed) 2011 stack_space_to_allocate += 8; 2012 2013 /* If we have a non-local label, we need to be able to unwind to it, so 2014 store the current register stack pointer. Also store the return 2015 address if we do that. */ 2016 if (MMIX_CFUN_HAS_LANDING_PAD) 2017 stack_space_to_allocate += 16; 2018 else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS) 2019 /* If we do have a saved return-address slot, add room for it. */ 2020 stack_space_to_allocate += 8; 2021 2022 /* Make sure we don't get an unaligned stack. */ 2023 if ((stack_space_to_allocate % 8) != 0) 2024 internal_error ("stack frame not a multiple of 8 bytes: %wd", 2025 stack_space_to_allocate); 2026 2027 if (crtl->args.pretend_args_size) 2028 { 2029 int mmix_first_vararg_reg 2030 = (MMIX_FIRST_INCOMING_ARG_REGNUM 2031 + (MMIX_MAX_ARGS_IN_REGS 2032 - crtl->args.pretend_args_size / 8)); 2033 2034 for (regno 2035 = MMIX_FIRST_INCOMING_ARG_REGNUM + MMIX_MAX_ARGS_IN_REGS - 1; 2036 regno >= mmix_first_vararg_reg; 2037 regno--) 2038 { 2039 if (offset < 0) 2040 { 2041 HOST_WIDE_INT stack_chunk 2042 = stack_space_to_allocate > (256 - 8) 2043 ? (256 - 8) : stack_space_to_allocate; 2044 2045 mmix_emit_sp_add (-stack_chunk); 2046 offset += stack_chunk; 2047 stack_space_to_allocate -= stack_chunk; 2048 } 2049 2050 /* These registers aren't actually saved (as in "will be 2051 restored"), so don't tell DWARF2 they're saved. */ 2052 emit_move_insn (gen_rtx_MEM (DImode, 2053 plus_constant (Pmode, stack_pointer_rtx, 2054 offset)), 2055 gen_rtx_REG (DImode, regno)); 2056 offset -= 8; 2057 } 2058 } 2059 2060 /* Store the frame-pointer. */ 2061 2062 if (frame_pointer_needed) 2063 { 2064 rtx insn; 2065 2066 if (offset < 0) 2067 { 2068 /* Get 8 less than otherwise, since we need to reach offset + 8. */ 2069 HOST_WIDE_INT stack_chunk 2070 = stack_space_to_allocate > (256 - 8 - 8) 2071 ? (256 - 8 - 8) : stack_space_to_allocate; 2072 2073 mmix_emit_sp_add (-stack_chunk); 2074 2075 offset += stack_chunk; 2076 stack_space_to_allocate -= stack_chunk; 2077 } 2078 2079 insn = emit_move_insn (gen_rtx_MEM (DImode, 2080 plus_constant (Pmode, 2081 stack_pointer_rtx, 2082 offset)), 2083 hard_frame_pointer_rtx); 2084 RTX_FRAME_RELATED_P (insn) = 1; 2085 insn = emit_insn (gen_adddi3 (hard_frame_pointer_rtx, 2086 stack_pointer_rtx, 2087 GEN_INT (offset + 8))); 2088 RTX_FRAME_RELATED_P (insn) = 1; 2089 offset -= 8; 2090 } 2091 2092 if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS) 2093 { 2094 rtx tmpreg, retreg; 2095 rtx insn; 2096 2097 /* Store the return-address, if one is needed on the stack. We 2098 usually store it in a register when needed, but that doesn't work 2099 with -fexceptions. */ 2100 2101 if (offset < 0) 2102 { 2103 /* Get 8 less than otherwise, since we need to reach offset + 8. */ 2104 HOST_WIDE_INT stack_chunk 2105 = stack_space_to_allocate > (256 - 8 - 8) 2106 ? (256 - 8 - 8) : stack_space_to_allocate; 2107 2108 mmix_emit_sp_add (-stack_chunk); 2109 2110 offset += stack_chunk; 2111 stack_space_to_allocate -= stack_chunk; 2112 } 2113 2114 tmpreg = gen_rtx_REG (DImode, 255); 2115 retreg = gen_rtx_REG (DImode, MMIX_rJ_REGNUM); 2116 2117 /* Dwarf2 code is confused by the use of a temporary register for 2118 storing the return address, so we have to express it as a note, 2119 which we attach to the actual store insn. */ 2120 emit_move_insn (tmpreg, retreg); 2121 2122 insn = emit_move_insn (gen_rtx_MEM (DImode, 2123 plus_constant (Pmode, 2124 stack_pointer_rtx, 2125 offset)), 2126 tmpreg); 2127 RTX_FRAME_RELATED_P (insn) = 1; 2128 add_reg_note (insn, REG_FRAME_RELATED_EXPR, 2129 gen_rtx_SET (gen_rtx_MEM (DImode, 2130 plus_constant (Pmode, 2131 stack_pointer_rtx, 2132 offset)), 2133 retreg)); 2134 2135 offset -= 8; 2136 } 2137 else if (MMIX_CFUN_HAS_LANDING_PAD) 2138 offset -= 8; 2139 2140 if (MMIX_CFUN_HAS_LANDING_PAD) 2141 { 2142 /* Store the register defining the numbering of local registers, so 2143 we know how long to unwind the register stack. */ 2144 2145 if (offset < 0) 2146 { 2147 /* Get 8 less than otherwise, since we need to reach offset + 8. */ 2148 HOST_WIDE_INT stack_chunk 2149 = stack_space_to_allocate > (256 - 8 - 8) 2150 ? (256 - 8 - 8) : stack_space_to_allocate; 2151 2152 mmix_emit_sp_add (-stack_chunk); 2153 2154 offset += stack_chunk; 2155 stack_space_to_allocate -= stack_chunk; 2156 } 2157 2158 /* We don't tell dwarf2 about this one; we just have it to unwind 2159 the register stack at landing pads. FIXME: It's a kludge because 2160 we can't describe the effect of the PUSHJ and PUSHGO insns on the 2161 register stack at the moment. Best thing would be to handle it 2162 like stack-pointer offsets. Better: some hook into dwarf2out.c 2163 to produce DW_CFA_expression:s that specify the increment of rO, 2164 and unwind it at eh_return (preferred) or at the landing pad. 2165 Then saves to $0..$G-1 could be specified through that register. */ 2166 2167 emit_move_insn (gen_rtx_REG (DImode, 255), 2168 gen_rtx_REG (DImode, 2169 MMIX_rO_REGNUM)); 2170 emit_move_insn (gen_rtx_MEM (DImode, 2171 plus_constant (Pmode, stack_pointer_rtx, 2172 offset)), 2173 gen_rtx_REG (DImode, 255)); 2174 offset -= 8; 2175 } 2176 2177 /* After the return-address and the frame-pointer, we have the local 2178 variables. They're the ones that may have an "unaligned" size. */ 2179 offset -= (locals_size + 7) & ~7; 2180 2181 /* Now store all registers that are global, i.e. not saved by the 2182 register file machinery. 2183 2184 It is assumed that the frame-pointer is one of these registers, so it 2185 is explicitly excluded in the count. */ 2186 2187 for (regno = 255; 2188 regno >= MMIX_FIRST_GLOBAL_REGNUM; 2189 regno--) 2190 if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed) 2191 && df_regs_ever_live_p (regno) && ! call_used_regs[regno]) 2192 || IS_MMIX_EH_RETURN_DATA_REG (regno)) 2193 { 2194 rtx insn; 2195 2196 if (offset < 0) 2197 { 2198 HOST_WIDE_INT stack_chunk 2199 = (stack_space_to_allocate > (256 - offset - 8) 2200 ? (256 - offset - 8) : stack_space_to_allocate); 2201 2202 mmix_emit_sp_add (-stack_chunk); 2203 offset += stack_chunk; 2204 stack_space_to_allocate -= stack_chunk; 2205 } 2206 2207 insn = emit_move_insn (gen_rtx_MEM (DImode, 2208 plus_constant (Pmode, 2209 stack_pointer_rtx, 2210 offset)), 2211 gen_rtx_REG (DImode, regno)); 2212 RTX_FRAME_RELATED_P (insn) = 1; 2213 offset -= 8; 2214 } 2215 2216 /* Finally, allocate room for outgoing args and local vars if room 2217 wasn't allocated above. */ 2218 if (stack_space_to_allocate) 2219 mmix_emit_sp_add (-stack_space_to_allocate); 2220} 2221 2222/* Expands the function epilogue into RTX. */ 2223 2224void 2225mmix_expand_epilogue (void) 2226{ 2227 HOST_WIDE_INT locals_size = get_frame_size (); 2228 int regno; 2229 HOST_WIDE_INT stack_space_to_deallocate 2230 = (crtl->outgoing_args_size 2231 + crtl->args.pretend_args_size 2232 + locals_size + 7) & ~7; 2233 2234 /* The first address to access is beyond the outgoing_args area. */ 2235 HOST_WIDE_INT offset = crtl->outgoing_args_size; 2236 2237 /* Add the space for global non-register-stack registers. 2238 It is assumed that the frame-pointer register can be one of these 2239 registers, in which case it is excluded from the count when needed. */ 2240 for (regno = 255; 2241 regno >= MMIX_FIRST_GLOBAL_REGNUM; 2242 regno--) 2243 if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed) 2244 && df_regs_ever_live_p (regno) && !call_used_regs[regno]) 2245 || IS_MMIX_EH_RETURN_DATA_REG (regno)) 2246 stack_space_to_deallocate += 8; 2247 2248 /* Add in the space for register stack-pointer. If so, always add room 2249 for the saved PC. */ 2250 if (MMIX_CFUN_HAS_LANDING_PAD) 2251 stack_space_to_deallocate += 16; 2252 else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS) 2253 /* If we have a saved return-address slot, add it in. */ 2254 stack_space_to_deallocate += 8; 2255 2256 /* Add in the frame-pointer. */ 2257 if (frame_pointer_needed) 2258 stack_space_to_deallocate += 8; 2259 2260 /* Make sure we don't get an unaligned stack. */ 2261 if ((stack_space_to_deallocate % 8) != 0) 2262 internal_error ("stack frame not a multiple of octabyte: %wd", 2263 stack_space_to_deallocate); 2264 2265 /* We will add back small offsets to the stack pointer as we go. 2266 First, we restore all registers that are global, i.e. not saved by 2267 the register file machinery. */ 2268 2269 for (regno = MMIX_FIRST_GLOBAL_REGNUM; 2270 regno <= 255; 2271 regno++) 2272 if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed) 2273 && df_regs_ever_live_p (regno) && !call_used_regs[regno]) 2274 || IS_MMIX_EH_RETURN_DATA_REG (regno)) 2275 { 2276 if (offset > 255) 2277 { 2278 mmix_emit_sp_add (offset); 2279 stack_space_to_deallocate -= offset; 2280 offset = 0; 2281 } 2282 2283 emit_move_insn (gen_rtx_REG (DImode, regno), 2284 gen_rtx_MEM (DImode, 2285 plus_constant (Pmode, stack_pointer_rtx, 2286 offset))); 2287 offset += 8; 2288 } 2289 2290 /* Here is where the local variables were. As in the prologue, they 2291 might be of an unaligned size. */ 2292 offset += (locals_size + 7) & ~7; 2293 2294 /* The saved register stack pointer is just below the frame-pointer 2295 register. We don't need to restore it "manually"; the POP 2296 instruction does that. */ 2297 if (MMIX_CFUN_HAS_LANDING_PAD) 2298 offset += 16; 2299 else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS) 2300 /* The return-address slot is just below the frame-pointer register. 2301 We don't need to restore it because we don't really use it. */ 2302 offset += 8; 2303 2304 /* Get back the old frame-pointer-value. */ 2305 if (frame_pointer_needed) 2306 { 2307 if (offset > 255) 2308 { 2309 mmix_emit_sp_add (offset); 2310 2311 stack_space_to_deallocate -= offset; 2312 offset = 0; 2313 } 2314 2315 emit_move_insn (hard_frame_pointer_rtx, 2316 gen_rtx_MEM (DImode, 2317 plus_constant (Pmode, stack_pointer_rtx, 2318 offset))); 2319 offset += 8; 2320 } 2321 2322 /* We do not need to restore pretended incoming args, just add back 2323 offset to sp. */ 2324 if (stack_space_to_deallocate != 0) 2325 mmix_emit_sp_add (stack_space_to_deallocate); 2326 2327 if (crtl->calls_eh_return) 2328 /* Adjust the (normal) stack-pointer to that of the receiver. 2329 FIXME: It would be nice if we could also adjust the register stack 2330 here, but we need to express it through DWARF 2 too. */ 2331 emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, 2332 gen_rtx_REG (DImode, 2333 MMIX_EH_RETURN_STACKADJ_REGNUM))); 2334} 2335 2336/* Output an optimal sequence for setting a register to a specific 2337 constant. Used in an alternative for const_ints in movdi, and when 2338 using large stack-frame offsets. 2339 2340 Use do_begin_end to say if a line-starting TAB and newline before the 2341 first insn and after the last insn is wanted. */ 2342 2343void 2344mmix_output_register_setting (FILE *stream, 2345 int regno, 2346 int64_t value, 2347 int do_begin_end) 2348{ 2349 if (do_begin_end) 2350 fprintf (stream, "\t"); 2351 2352 if (insn_const_int_ok_for_constraint (value, CONSTRAINT_K)) 2353 fprintf (stream, "NEGU %s,0,%" PRId64, reg_names[regno], -value); 2354 else if (mmix_shiftable_wyde_value ((uint64_t) value)) 2355 { 2356 /* First, the one-insn cases. */ 2357 mmix_output_shiftvalue_op_from_str (stream, "SET", 2358 (uint64_t) 2359 value); 2360 fprintf (stream, " %s,", reg_names[regno]); 2361 mmix_output_shifted_value (stream, (uint64_t) value); 2362 } 2363 else if (mmix_shiftable_wyde_value (-(uint64_t) value)) 2364 { 2365 /* We do this to get a bit more legible assembly code. The next 2366 alternative is mostly redundant with this. */ 2367 2368 mmix_output_shiftvalue_op_from_str (stream, "SET", 2369 -(uint64_t) 2370 value); 2371 fprintf (stream, " %s,", reg_names[regno]); 2372 mmix_output_shifted_value (stream, -(uint64_t) value); 2373 fprintf (stream, "\n\tNEGU %s,0,%s", reg_names[regno], 2374 reg_names[regno]); 2375 } 2376 else if (mmix_shiftable_wyde_value (~(uint64_t) value)) 2377 { 2378 /* Slightly more expensive, the two-insn cases. */ 2379 2380 /* FIXME: We could of course also test if 0..255-N or ~(N | 1..255) 2381 is shiftable, or any other one-insn transformation of the value. 2382 FIXME: Check first if the value is "shiftable" by two loading 2383 with two insns, since it makes more readable assembly code (if 2384 anyone else cares). */ 2385 2386 mmix_output_shiftvalue_op_from_str (stream, "SET", 2387 ~(uint64_t) 2388 value); 2389 fprintf (stream, " %s,", reg_names[regno]); 2390 mmix_output_shifted_value (stream, ~(uint64_t) value); 2391 fprintf (stream, "\n\tNOR %s,%s,0", reg_names[regno], 2392 reg_names[regno]); 2393 } 2394 else 2395 { 2396 /* The generic case. 2..4 insns. */ 2397 static const char *const higher_parts[] = {"L", "ML", "MH", "H"}; 2398 const char *op = "SET"; 2399 const char *line_begin = ""; 2400 int insns = 0; 2401 int i; 2402 int64_t tmpvalue = value; 2403 2404 /* Compute the number of insns needed to output this constant. */ 2405 for (i = 0; i < 4 && tmpvalue != 0; i++) 2406 { 2407 if (tmpvalue & 65535) 2408 insns++; 2409 tmpvalue >>= 16; 2410 } 2411 if (TARGET_BASE_ADDRESSES && insns == 3) 2412 { 2413 /* The number three is based on a static observation on 2414 ghostscript-6.52. Two and four are excluded because there 2415 are too many such constants, and each unique constant (maybe 2416 offset by 1..255) were used few times compared to other uses, 2417 e.g. addresses. 2418 2419 We use base-plus-offset addressing to force it into a global 2420 register; we just use a "LDA reg,VALUE", which will cause the 2421 assembler and linker to DTRT (for constants as well as 2422 addresses). */ 2423 fprintf (stream, "LDA %s,", reg_names[regno]); 2424 mmix_output_octa (stream, value, 0); 2425 } 2426 else 2427 { 2428 /* Output pertinent parts of the 4-wyde sequence. 2429 Still more to do if we want this to be optimal, but hey... 2430 Note that the zero case has been handled above. */ 2431 for (i = 0; i < 4 && value != 0; i++) 2432 { 2433 if (value & 65535) 2434 { 2435 fprintf (stream, "%s%s%s %s,#%x", line_begin, op, 2436 higher_parts[i], reg_names[regno], 2437 (int) (value & 65535)); 2438 /* The first one sets the rest of the bits to 0, the next 2439 ones add set bits. */ 2440 op = "INC"; 2441 line_begin = "\n\t"; 2442 } 2443 2444 value >>= 16; 2445 } 2446 } 2447 } 2448 2449 if (do_begin_end) 2450 fprintf (stream, "\n"); 2451} 2452 2453/* Return 1 if value is 0..65535*2**(16*N) for N=0..3. 2454 else return 0. */ 2455 2456int 2457mmix_shiftable_wyde_value (uint64_t value) 2458{ 2459 /* Shift by 16 bits per group, stop when we've found two groups with 2460 nonzero bits. */ 2461 int i; 2462 int has_candidate = 0; 2463 2464 for (i = 0; i < 4; i++) 2465 { 2466 if (value & 65535) 2467 { 2468 if (has_candidate) 2469 return 0; 2470 else 2471 has_candidate = 1; 2472 } 2473 2474 value >>= 16; 2475 } 2476 2477 return 1; 2478} 2479 2480/* X and Y are two things to compare using CODE. Return the rtx for 2481 the cc-reg in the proper mode. */ 2482 2483rtx 2484mmix_gen_compare_reg (RTX_CODE code, rtx x, rtx y) 2485{ 2486 machine_mode ccmode = SELECT_CC_MODE (code, x, y); 2487 return gen_reg_rtx (ccmode); 2488} 2489 2490/* Local (static) helper functions. */ 2491 2492static void 2493mmix_emit_sp_add (HOST_WIDE_INT offset) 2494{ 2495 rtx insn; 2496 2497 if (offset < 0) 2498 { 2499 /* Negative stack-pointer adjustments are allocations and appear in 2500 the prologue only. We mark them as frame-related so unwind and 2501 debug info is properly emitted for them. */ 2502 if (offset > -255) 2503 insn = emit_insn (gen_adddi3 (stack_pointer_rtx, 2504 stack_pointer_rtx, 2505 GEN_INT (offset))); 2506 else 2507 { 2508 rtx tmpr = gen_rtx_REG (DImode, 255); 2509 RTX_FRAME_RELATED_P (emit_move_insn (tmpr, GEN_INT (offset))) = 1; 2510 insn = emit_insn (gen_adddi3 (stack_pointer_rtx, 2511 stack_pointer_rtx, tmpr)); 2512 } 2513 RTX_FRAME_RELATED_P (insn) = 1; 2514 } 2515 else 2516 { 2517 /* Positive adjustments are in the epilogue only. Don't mark them 2518 as "frame-related" for unwind info. */ 2519 if (insn_const_int_ok_for_constraint (offset, CONSTRAINT_L)) 2520 emit_insn (gen_adddi3 (stack_pointer_rtx, 2521 stack_pointer_rtx, 2522 GEN_INT (offset))); 2523 else 2524 { 2525 rtx tmpr = gen_rtx_REG (DImode, 255); 2526 emit_move_insn (tmpr, GEN_INT (offset)); 2527 insn = emit_insn (gen_adddi3 (stack_pointer_rtx, 2528 stack_pointer_rtx, tmpr)); 2529 } 2530 } 2531} 2532 2533/* Print operator suitable for doing something with a shiftable 2534 wyde. The type of operator is passed as an asm output modifier. */ 2535 2536static void 2537mmix_output_shiftvalue_op_from_str (FILE *stream, 2538 const char *mainop, 2539 int64_t value) 2540{ 2541 static const char *const op_part[] = {"L", "ML", "MH", "H"}; 2542 int i; 2543 2544 if (! mmix_shiftable_wyde_value (value)) 2545 { 2546 char s[sizeof ("0xffffffffffffffff")]; 2547 sprintf (s, "%#" PRIx64, value); 2548 internal_error ("MMIX Internal: %s is not a shiftable int", s); 2549 } 2550 2551 for (i = 0; i < 4; i++) 2552 { 2553 /* We know we're through when we find one-bits in the low 2554 16 bits. */ 2555 if (value & 0xffff) 2556 { 2557 fprintf (stream, "%s%s", mainop, op_part[i]); 2558 return; 2559 } 2560 value >>= 16; 2561 } 2562 2563 /* No bits set? Then it must have been zero. */ 2564 fprintf (stream, "%sL", mainop); 2565} 2566 2567/* Print a 64-bit value, optionally prefixed by assembly pseudo. */ 2568 2569static void 2570mmix_output_octa (FILE *stream, int64_t value, int do_begin_end) 2571{ 2572 if (do_begin_end) 2573 fprintf (stream, "\tOCTA "); 2574 2575 /* Provide a few alternative output formats depending on the number, to 2576 improve legibility of assembler output. */ 2577 if ((value < (int64_t) 0 && value > (int64_t) -10000) 2578 || (value >= (int64_t) 0 && value <= (int64_t) 16384)) 2579 fprintf (stream, "%d", (int) value); 2580 else if (value > (int64_t) 0 2581 && value < ((int64_t) 1 << 31) * 2) 2582 fprintf (stream, "#%x", (unsigned int) value); 2583 else if (sizeof (HOST_WIDE_INT) == sizeof (int64_t)) 2584 /* We need to avoid the not-so-universal "0x" prefix; we need the 2585 pure hex-digits together with the mmixal "#" hex prefix. */ 2586 fprintf (stream, "#" HOST_WIDE_INT_PRINT_HEX_PURE, 2587 (HOST_WIDE_INT) value); 2588 else /* Need to avoid the hex output; there's no ...WIDEST...HEX_PURE. */ 2589 fprintf (stream, "%" PRIu64, value); 2590 2591 if (do_begin_end) 2592 fprintf (stream, "\n"); 2593} 2594 2595/* Print the presumed shiftable wyde argument shifted into place (to 2596 be output with an operand). */ 2597 2598static void 2599mmix_output_shifted_value (FILE *stream, int64_t value) 2600{ 2601 int i; 2602 2603 if (! mmix_shiftable_wyde_value (value)) 2604 { 2605 char s[16+2+1]; 2606 sprintf (s, "%#" PRIx64, value); 2607 internal_error ("MMIX Internal: %s is not a shiftable int", s); 2608 } 2609 2610 for (i = 0; i < 4; i++) 2611 { 2612 /* We know we're through when we find one-bits in the low 16 bits. */ 2613 if (value & 0xffff) 2614 { 2615 fprintf (stream, "#%x", (int) (value & 0xffff)); 2616 return; 2617 } 2618 2619 value >>= 16; 2620 } 2621 2622 /* No bits set? Then it must have been zero. */ 2623 fprintf (stream, "0"); 2624} 2625 2626/* Output an MMIX condition name corresponding to an operator 2627 and operands: 2628 (comparison_operator [(comparison_operator ...) (const_int 0)]) 2629 which means we have to look at *two* operators. 2630 2631 The argument "reversed" refers to reversal of the condition (not the 2632 same as swapping the arguments). */ 2633 2634static void 2635mmix_output_condition (FILE *stream, const_rtx x, int reversed) 2636{ 2637 struct cc_conv 2638 { 2639 RTX_CODE cc; 2640 2641 /* The normal output cc-code. */ 2642 const char *const normal; 2643 2644 /* The reversed cc-code, or NULL if invalid. */ 2645 const char *const reversed; 2646 }; 2647 2648 struct cc_type_conv 2649 { 2650 machine_mode cc_mode; 2651 2652 /* Terminated with {UNKNOWN, NULL, NULL} */ 2653 const struct cc_conv *const convs; 2654 }; 2655 2656#undef CCEND 2657#define CCEND {UNKNOWN, NULL, NULL} 2658 2659 static const struct cc_conv cc_fun_convs[] 2660 = {{ORDERED, "Z", "P"}, 2661 {UNORDERED, "P", "Z"}, 2662 CCEND}; 2663 static const struct cc_conv cc_fp_convs[] 2664 = {{GT, "P", NULL}, 2665 {LT, "N", NULL}, 2666 CCEND}; 2667 static const struct cc_conv cc_fpeq_convs[] 2668 = {{NE, "Z", "P"}, 2669 {EQ, "P", "Z"}, 2670 CCEND}; 2671 static const struct cc_conv cc_uns_convs[] 2672 = {{GEU, "NN", "N"}, 2673 {GTU, "P", "NP"}, 2674 {LEU, "NP", "P"}, 2675 {LTU, "N", "NN"}, 2676 CCEND}; 2677 static const struct cc_conv cc_signed_convs[] 2678 = {{NE, "NZ", "Z"}, 2679 {EQ, "Z", "NZ"}, 2680 {GE, "NN", "N"}, 2681 {GT, "P", "NP"}, 2682 {LE, "NP", "P"}, 2683 {LT, "N", "NN"}, 2684 CCEND}; 2685 static const struct cc_conv cc_di_convs[] 2686 = {{NE, "NZ", "Z"}, 2687 {EQ, "Z", "NZ"}, 2688 {GE, "NN", "N"}, 2689 {GT, "P", "NP"}, 2690 {LE, "NP", "P"}, 2691 {LT, "N", "NN"}, 2692 {GTU, "NZ", "Z"}, 2693 {LEU, "Z", "NZ"}, 2694 CCEND}; 2695#undef CCEND 2696 2697 static const struct cc_type_conv cc_convs[] 2698 = {{E_CC_FUNmode, cc_fun_convs}, 2699 {E_CC_FPmode, cc_fp_convs}, 2700 {E_CC_FPEQmode, cc_fpeq_convs}, 2701 {E_CC_UNSmode, cc_uns_convs}, 2702 {E_CCmode, cc_signed_convs}, 2703 {E_DImode, cc_di_convs}}; 2704 2705 size_t i; 2706 int j; 2707 2708 machine_mode mode = GET_MODE (XEXP (x, 0)); 2709 RTX_CODE cc = GET_CODE (x); 2710 2711 for (i = 0; i < ARRAY_SIZE (cc_convs); i++) 2712 { 2713 if (mode == cc_convs[i].cc_mode) 2714 { 2715 for (j = 0; cc_convs[i].convs[j].cc != UNKNOWN; j++) 2716 if (cc == cc_convs[i].convs[j].cc) 2717 { 2718 const char *mmix_cc 2719 = (reversed ? cc_convs[i].convs[j].reversed 2720 : cc_convs[i].convs[j].normal); 2721 2722 if (mmix_cc == NULL) 2723 fatal_insn ("MMIX Internal: Trying to output invalidly\ 2724 reversed condition:", x); 2725 2726 fprintf (stream, "%s", mmix_cc); 2727 return; 2728 } 2729 2730 fatal_insn ("MMIX Internal: What's the CC of this?", x); 2731 } 2732 } 2733 2734 fatal_insn ("MMIX Internal: What is the CC of this?", x); 2735} 2736 2737/* Return the bit-value for a const_int or const_double. */ 2738 2739int64_t 2740mmix_intval (const_rtx x) 2741{ 2742 if (GET_CODE (x) == CONST_INT) 2743 return INTVAL (x); 2744 2745 /* We make a little song and dance because converting to long long in 2746 gcc-2.7.2 is broken. I still want people to be able to use it for 2747 cross-compilation to MMIX. */ 2748 if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == VOIDmode) 2749 return CONST_DOUBLE_HIGH (x); 2750 2751 if (GET_CODE (x) == CONST_DOUBLE) 2752 { 2753 if (GET_MODE (x) == DFmode) 2754 { 2755 long bits[2]; 2756 2757 REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (x), bits); 2758 2759 /* The double cast is necessary to avoid getting the long 2760 sign-extended to unsigned long long(!) when they're of 2761 different size (usually 32-bit hosts). */ 2762 return 2763 ((uint64_t) (unsigned long) bits[0] 2764 << (uint64_t) 32U) 2765 | (uint64_t) (unsigned long) bits[1]; 2766 } 2767 else if (GET_MODE (x) == SFmode) 2768 { 2769 long bits; 2770 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x), bits); 2771 2772 return (unsigned long) bits; 2773 } 2774 } 2775 2776 fatal_insn ("MMIX Internal: This is not a constant:", x); 2777} 2778 2779/* Worker function for TARGET_PROMOTE_FUNCTION_MODE. */ 2780 2781machine_mode 2782mmix_promote_function_mode (const_tree type ATTRIBUTE_UNUSED, 2783 machine_mode mode, 2784 int *punsignedp ATTRIBUTE_UNUSED, 2785 const_tree fntype ATTRIBUTE_UNUSED, 2786 int for_return) 2787{ 2788 /* Apparently not doing TRT if int < register-size. FIXME: Perhaps 2789 FUNCTION_VALUE and LIBCALL_VALUE needs tweaking as some ports say. */ 2790 if (for_return == 1) 2791 return mode; 2792 2793 /* Promotion of modes currently generates slow code, extending before 2794 operation, so we do it only for arguments. */ 2795 if (GET_MODE_CLASS (mode) == MODE_INT 2796 && GET_MODE_SIZE (mode) < 8) 2797 return DImode; 2798 else 2799 return mode; 2800} 2801/* Worker function for TARGET_STRUCT_VALUE_RTX. */ 2802 2803static rtx 2804mmix_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED, 2805 int incoming ATTRIBUTE_UNUSED) 2806{ 2807 return gen_rtx_REG (Pmode, MMIX_STRUCT_VALUE_REGNUM); 2808} 2809 2810/* Worker function for TARGET_FRAME_POINTER_REQUIRED. 2811 2812 FIXME: Is this requirement built-in? Anyway, we should try to get rid 2813 of it; we can deduce the value. */ 2814 2815bool 2816mmix_frame_pointer_required (void) 2817{ 2818 return (cfun->has_nonlocal_label); 2819} 2820 2821/* 2822 * Local variables: 2823 * eval: (c-set-style "gnu") 2824 * indent-tabs-mode: t 2825 * End: 2826 */ 2827