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