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