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