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