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