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