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