* varasm.c (assemble_real): Use REAL_VALUE_TO_x and assemble_integer
[official-gcc.git] / gcc / config / mmix / mmix.c
blob3269d5b407503fa1a813fc00687cdd58accf7494
1 /* Definitions of target machine for GNU compiler, for MMIX.
2 Copyright (C) 2000, 2001 Free Software Foundation, Inc.
3 Contributed by Hans-Peter Nilsson (hp@bitrange.com)
5 This file is part of GNU CC.
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 #include "config.h"
23 #include "system.h"
24 #include "rtl.h"
25 #include "regs.h"
26 #include "hard-reg-set.h"
27 #include "hashtab.h"
28 #include "insn-config.h"
29 #include "output.h"
30 #include "flags.h"
31 #include "tree.h"
32 #include "function.h"
33 #include "expr.h"
34 #include "toplev.h"
35 #include "recog.h"
36 #include "ggc.h"
37 #include "dwarf2.h"
38 #include "debug.h"
39 #include "tm_p.h"
40 #include "integrate.h"
41 #include "target.h"
42 #include "target-def.h"
44 /* First some local helper definitions. */
45 #define MMIX_FIRST_GLOBAL_REGNUM 32
47 /* We'd need a current_function_has_landing_pad. It's marked as such when
48 a nonlocal_goto_receiver is expanded. Not just a C++ thing, but
49 mostly. */
50 #define MMIX_CFUN_HAS_LANDING_PAD (cfun->machine->has_landing_pad != 0)
52 /* We have no means to tell DWARF 2 about the register stack, so we need
53 to store the return address on the stack if an exception can get into
54 this function. FIXME: Narrow condition. */
55 #define MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS \
56 (flag_exceptions && ! leaf_function_p ())
58 #define IS_MMIX_EH_RETURN_DATA_REG(REGNO) \
59 (current_function_calls_eh_return \
60 && (EH_RETURN_DATA_REGNO (0) == REGNO \
61 || EH_RETURN_DATA_REGNO (1) == REGNO \
62 || EH_RETURN_DATA_REGNO (2) == REGNO \
63 || EH_RETURN_DATA_REGNO (3) == REGNO))
65 /* The canonical saved comparison operands for non-cc0 machines, set in
66 the compare expander. */
67 rtx mmix_compare_op0;
68 rtx mmix_compare_op1;
70 /* We ignore some options with arguments. They are passed to the linker,
71 but also ends up here because they start with "-m". We tell the driver
72 to store them in a variable we don't inspect. */
73 const char *mmix_cc1_ignored_option;
75 /* Declarations of locals. */
77 /* This is used in the prologue for what number to pass in a PUSHJ or
78 PUSHGO insn. */
79 static int mmix_highest_saved_stack_register;
81 /* Intermediate for insn output. */
82 static int mmix_output_destination_register;
84 static void mmix_output_shiftvalue_op_from_str
85 PARAMS ((FILE *, const char *, HOST_WIDEST_INT));
86 static void mmix_output_shifted_value PARAMS ((FILE *, HOST_WIDEST_INT));
87 static void mmix_output_condition PARAMS ((FILE *, rtx, int));
88 static HOST_WIDEST_INT mmix_intval PARAMS ((rtx));
89 static void mmix_output_octa PARAMS ((FILE *, HOST_WIDEST_INT, int));
90 static bool mmix_assemble_integer PARAMS ((rtx, unsigned int, int));
91 static void mmix_init_machine_status PARAMS ((struct function *));
93 extern void mmix_target_asm_function_prologue
94 PARAMS ((FILE *, HOST_WIDE_INT));
95 extern void mmix_target_asm_function_epilogue
96 PARAMS ((FILE *, HOST_WIDE_INT));
99 /* Target structure macros. Listed by node. See `Using and Porting GCC'
100 for a general description. */
102 /* Node: Function Entry */
104 #undef TARGET_ASM_BYTE_OP
105 #define TARGET_ASM_BYTE_OP NULL
106 #undef TARGET_ASM_ALIGNED_HI_OP
107 #define TARGET_ASM_ALIGNED_HI_OP NULL
108 #undef TARGET_ASM_ALIGNED_SI_OP
109 #define TARGET_ASM_ALIGNED_SI_OP NULL
110 #undef TARGET_ASM_ALIGNED_DI_OP
111 #define TARGET_ASM_ALIGNED_DI_OP NULL
112 #undef TARGET_ASM_INTEGER
113 #define TARGET_ASM_INTEGER mmix_assemble_integer
115 #undef TARGET_ASM_FUNCTION_PROLOGUE
116 #define TARGET_ASM_FUNCTION_PROLOGUE mmix_target_asm_function_prologue
118 #undef TARGET_ASM_FUNCTION_EPILOGUE
119 #define TARGET_ASM_FUNCTION_EPILOGUE mmix_target_asm_function_epilogue
121 struct gcc_target targetm = TARGET_INITIALIZER;
123 /* Functions that are expansions for target macros.
124 See Target Macros in `Using and Porting GCC'. */
126 /* OVERRIDE_OPTIONS. */
128 void
129 mmix_override_options ()
131 /* Should we err or should we warn? Hmm. At least we must neutralize
132 it. For example the wrong kind of case-tables will be generated with
133 PIC; we use absolute address items for mmixal compatibility. FIXME:
134 They could be relative if we just elide them to after all pertinent
135 labels. */
136 if (flag_pic)
138 warning ("-f%s not supported: ignored", (flag_pic > 1) ? "PIC" : "pic");
139 flag_pic = 0;
142 /* All other targets add GC roots from their override_options function,
143 so play along. */
144 ggc_add_rtx_root (&mmix_compare_op0, 1);
145 ggc_add_rtx_root (&mmix_compare_op1, 1);
148 /* INIT_EXPANDERS. */
150 void
151 mmix_init_expanders ()
153 init_machine_status = mmix_init_machine_status;
156 /* Set the per-function data. */
158 static void
159 mmix_init_machine_status (f)
160 struct function *f;
162 f->machine = xcalloc (1, sizeof (struct machine_function));
165 /* DATA_ALIGNMENT.
166 We have trouble getting the address of stuff that is located at other
167 than 32-bit alignments (GETA requirements), so try to give everything
168 at least 32-bit alignment. */
171 mmix_data_alignment (type, basic_align)
172 tree type ATTRIBUTE_UNUSED;
173 int basic_align;
175 if (basic_align < 32)
176 return 32;
178 return basic_align;
181 /* CONSTANT_ALIGNMENT. */
184 mmix_constant_alignment (constant, basic_align)
185 tree constant ATTRIBUTE_UNUSED;
186 int basic_align;
188 if (basic_align < 32)
189 return 32;
191 return basic_align;
194 /* LOCAL_ALIGNMENT. */
197 mmix_local_alignment (type, basic_align)
198 tree type ATTRIBUTE_UNUSED;
199 int basic_align;
201 if (basic_align < 32)
202 return 32;
204 return basic_align;
207 /* CONDITIONAL_REGISTER_USAGE. */
209 void
210 mmix_conditional_register_usage ()
212 int i;
214 if (TARGET_ABI_GNU)
216 static const int gnu_abi_reg_alloc_order[]
217 = MMIX_GNU_ABI_REG_ALLOC_ORDER;
219 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
220 reg_alloc_order[i] = gnu_abi_reg_alloc_order[i];
222 /* Change the default from the mmixware ABI. For the GNU ABI,
223 $15..$30 are call-saved just as $0..$14. There must be one
224 call-clobbered local register for the "hole" describing number of
225 saved local registers saved by PUSHJ/PUSHGO during the function
226 call, receiving the return value at return. So best is to use
227 the highest, $31. It's already marked call-clobbered for the
228 mmixware ABI. */
229 for (i = 15; i <= 30; i++)
230 call_used_regs[i] = 0;
233 /* Step over the ":" in special register names. */
234 if (! TARGET_TOPLEVEL_SYMBOLS)
235 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
236 if (reg_names[i][0] == ':')
237 reg_names[i]++;
240 /* PREFERRED_RELOAD_CLASS.
241 We need to extend the reload class of REMAINDER_REG and HIMULT_REG. */
243 enum reg_class
244 mmix_preferred_reload_class (x, class)
245 rtx x ATTRIBUTE_UNUSED;
246 enum reg_class class;
248 /* FIXME: Revisit. */
249 return GET_CODE (x) == MOD && GET_MODE (x) == DImode
250 ? REMAINDER_REG : class;
253 /* PREFERRED_OUTPUT_RELOAD_CLASS.
254 We need to extend the reload class of REMAINDER_REG and HIMULT_REG. */
256 enum reg_class
257 mmix_preferred_output_reload_class (x, class)
258 rtx x ATTRIBUTE_UNUSED;
259 enum reg_class class;
261 /* FIXME: Revisit. */
262 return GET_CODE (x) == MOD && GET_MODE (x) == DImode
263 ? REMAINDER_REG : class;
266 /* SECONDARY_RELOAD_CLASS.
267 We need to reload regs of REMAINDER_REG and HIMULT_REG elsewhere. */
269 enum reg_class
270 mmix_secondary_reload_class (class, mode, x, in_p)
271 enum reg_class class;
272 enum machine_mode mode;
273 rtx x;
274 int in_p;
276 if (class == REMAINDER_REG
277 || class == HIMULT_REG
278 || class == SYSTEM_REGS)
279 return GENERAL_REGS;
281 if (mode != DImode || in_p)
282 return NO_REGS;
284 /* We have to help reload. */
285 if (mode == DImode && GET_CODE (x) == MEM
286 && ! address_operand (XEXP (x, 0), GET_MODE (x)))
287 return GENERAL_REGS;
289 /* FIXME: Optimize this; there are lots of PLUS:es that don't need a
290 reload register. */
291 if (GET_CODE (x) == PLUS)
292 return GENERAL_REGS;
294 return NO_REGS;
297 /* CONST_OK_FOR_LETTER_P. */
300 mmix_const_ok_for_letter_p (value, c)
301 HOST_WIDE_INT value;
302 int c;
304 return
305 (c == 'I' ? value >= 0 && value <= 255
306 : c == 'J' ? value >= 0 && value <= 65535
307 : c == 'K' ? value <= 0 && value >= -255
308 : c == 'L' ? mmix_shiftable_wyde_value (value)
309 : c == 'M' ? value == 0
310 : c == 'N' ? mmix_shiftable_wyde_value (~value)
311 : c == 'O' ? (value == 3 || value == 5 || value == 9
312 || value == 17)
313 : 0);
316 /* CONST_DOUBLE_OK_FOR_LETTER_P. */
319 mmix_const_double_ok_for_letter_p (value, c)
320 rtx value;
321 int c;
323 return
324 (c == 'G' ? value == CONST0_RTX (GET_MODE (value))
325 : 0);
328 /* EXTRA_CONSTRAINT.
329 We need this since our constants are not always expressible as
330 CONST_INT:s, but rather often as CONST_DOUBLE:s. */
333 mmix_extra_constraint (x, c)
334 rtx x;
335 int c;
337 HOST_WIDEST_INT value;
339 if (c == 'U')
340 return address_operand (x, Pmode);
342 if (GET_CODE (x) != CONST_DOUBLE || GET_MODE (x) != VOIDmode)
343 return 0;
345 value = mmix_intval (x);
347 /* We used to map Q->J, R->K, S->L, T->N, U->O, but we don't have to any
348 more ('U' taken for address_operand). Some letters map outside of
349 CONST_INT, though; we still use 'S' and 'T'. */
350 if (c == 'S')
351 return mmix_shiftable_wyde_value (value);
352 else if (c == 'T')
353 return mmix_shiftable_wyde_value (~value);
354 return 0;
357 /* DYNAMIC_CHAIN_ADDRESS. */
360 mmix_dynamic_chain_address (frame)
361 rtx frame;
363 /* FIXME: the frame-pointer is stored at offset -8 from the current
364 frame-pointer. Unfortunately, the caller assumes that a
365 frame-pointer is present for *all* previous frames. There should be
366 a way to say that that cannot be done, like for RETURN_ADDR_RTX. */
367 return plus_constant (frame, -8);
370 /* STARTING_FRAME_OFFSET. */
373 mmix_starting_frame_offset ()
375 /* The old frame pointer is in the slot below the new one, so
376 FIRST_PARM_OFFSET does not need to depend on whether the
377 frame-pointer is needed or not. We have to adjust for the register
378 stack pointer being located below the saved frame pointer.
379 Similarly, we store the return address on the stack too, for
380 exception handling, and always if we save the register stack pointer. */
381 return
383 + (MMIX_CFUN_HAS_LANDING_PAD
384 ? -16 : (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS ? -8 : 0)));
387 /* RETURN_ADDR_RTX. */
390 mmix_return_addr_rtx (count, frame)
391 int count;
392 rtx frame ATTRIBUTE_UNUSED;
394 return count == 0
395 ? (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS
396 /* FIXME: Set frame_alias_set on the following. */
397 ? validize_mem (gen_rtx_MEM (Pmode, plus_constant (frame_pointer_rtx, -16)))
398 : get_hard_reg_initial_val (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM))
399 : NULL_RTX;
402 /* SETUP_FRAME_ADDRESSES. */
404 void
405 mmix_setup_frame_addresses ()
407 /* Nothing needed at the moment. */
410 /* The difference between the (imaginary) frame pointer and the stack
411 pointer. Used to eliminate the frame pointer. */
414 mmix_initial_elimination_offset (fromreg, toreg)
415 int fromreg;
416 int toreg;
418 int regno;
419 int fp_sp_offset
420 = (get_frame_size () + current_function_outgoing_args_size + 7) & ~7;
422 /* There is no actual difference between these two. */
423 if (fromreg == MMIX_ARG_POINTER_REGNUM
424 && toreg == MMIX_FRAME_POINTER_REGNUM)
425 return 0;
427 /* The difference is the size of local variables plus the size of
428 outgoing function arguments that would normally be passed as
429 registers but must be passed on stack because we're out of
430 function-argument registers. Only global saved registers are
431 counted; the others go on the register stack.
433 The frame-pointer is counted too if it is what is eliminated, as we
434 need to balance the offset for it from STARTING_FRAME_OFFSET.
436 Also add in the slot for the register stack pointer we save if we
437 have a landing pad.
439 Unfortunately, we can't access $0..$14, from unwinder code easily, so
440 store the return address in a frame slot too. FIXME: Only for
441 non-leaf functions. FIXME: Always with a landing pad, because it's
442 hard to know whether we need the other at the time we know we need
443 the offset for one (and have to state it). It's a kludge until we
444 can express the register stack in the EH frame info.
446 We have to do alignment here; get_frame_size will not return a
447 multiple of STACK_BOUNDARY. FIXME: Add note in manual. */
449 for (regno = MMIX_FIRST_GLOBAL_REGNUM;
450 regno <= 255;
451 regno++)
452 if ((regs_ever_live[regno] && ! call_used_regs[regno])
453 || IS_MMIX_EH_RETURN_DATA_REG (regno))
454 fp_sp_offset += 8;
456 return fp_sp_offset
457 + (MMIX_CFUN_HAS_LANDING_PAD
458 ? 16 : (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS ? 8 : 0))
459 + (fromreg == MMIX_ARG_POINTER_REGNUM ? 0 : 8);
462 /* Return an rtx for a function argument to go in a register, and 0 for
463 one that must go on stack. */
466 mmix_function_arg (argsp, mode, type, named, incoming)
467 const CUMULATIVE_ARGS * argsp;
468 enum machine_mode mode;
469 tree type;
470 int named ATTRIBUTE_UNUSED;
471 int incoming;
473 /* Handling of the positional dummy parameter for varargs gets nasty.
474 Check execute/991216-3 and function.c:assign_params. We have to say
475 that the dummy parameter goes on stack in order to get the correct
476 offset when va_start and va_arg is applied. FIXME: Should do TRT by
477 itself in the gcc core. */
478 if ((! named && incoming && current_function_varargs) || argsp->now_varargs)
479 return NULL_RTX;
481 /* Last-argument marker. */
482 if (type == void_type_node)
483 return (argsp->regs < MMIX_MAX_ARGS_IN_REGS)
484 ? gen_rtx_REG (mode,
485 (incoming
486 ? MMIX_FIRST_INCOMING_ARG_REGNUM
487 : MMIX_FIRST_ARG_REGNUM) + argsp->regs)
488 : NULL_RTX;
490 return (argsp->regs < MMIX_MAX_ARGS_IN_REGS
491 && !MUST_PASS_IN_STACK (mode, type)
492 && (GET_MODE_BITSIZE (mode) <= 64
493 || argsp->lib
494 || TARGET_LIBFUNC))
495 ? gen_rtx_REG (mode,
496 (incoming
497 ? MMIX_FIRST_INCOMING_ARG_REGNUM
498 : MMIX_FIRST_ARG_REGNUM)
499 + argsp->regs)
500 : NULL_RTX;
503 /* Returns nonzero for everything that goes by reference, 0 for
504 everything that goes by value. */
507 mmix_function_arg_pass_by_reference (argsp, mode, type, named)
508 const CUMULATIVE_ARGS * argsp;
509 enum machine_mode mode;
510 tree type;
511 int named ATTRIBUTE_UNUSED;
513 /* FIXME: Check: I'm not sure the MUST_PASS_IN_STACK check is
514 necessary. */
515 return
516 MUST_PASS_IN_STACK (mode, type)
517 || (MMIX_FUNCTION_ARG_SIZE (mode, type) > 8
518 && !TARGET_LIBFUNC
519 && !argsp->lib);
522 /* Return nonzero if regno is a register number where a parameter is
523 passed, and 0 otherwise. */
526 mmix_function_arg_regno_p (regno, incoming)
527 int regno;
528 int incoming;
530 int first_arg_regnum
531 = incoming ? MMIX_FIRST_INCOMING_ARG_REGNUM : MMIX_FIRST_ARG_REGNUM;
533 return regno >= first_arg_regnum
534 && regno < first_arg_regnum + MMIX_MAX_ARGS_IN_REGS;
537 /* FUNCTION_OUTGOING_VALUE. */
540 mmix_function_outgoing_value (valtype, func)
541 tree valtype;
542 tree func ATTRIBUTE_UNUSED;
544 enum machine_mode mode = TYPE_MODE (valtype);
545 enum machine_mode cmode;
546 int first_val_regnum = MMIX_OUTGOING_RETURN_VALUE_REGNUM;
547 rtx vec[MMIX_MAX_REGS_FOR_VALUE];
548 int i;
549 int nregs;
551 /* Return values that fit in a register need no special handling.
552 There's no register hole when parameters are passed in global
553 registers. */
554 if (TARGET_ABI_GNU
555 || GET_MODE_BITSIZE (mode) <= BITS_PER_WORD)
556 return
557 gen_rtx_REG (mode, MMIX_OUTGOING_RETURN_VALUE_REGNUM);
559 /* A complex type, made up of components. */
560 cmode = TYPE_MODE (TREE_TYPE (valtype));
561 nregs = ((GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD);
563 /* We need to take care of the effect of the register hole on return
564 values of large sizes; the last register will appear as the first
565 register, with the rest shifted. (For complex modes, this is just
566 swapped registers.) */
568 if (nregs > MMIX_MAX_REGS_FOR_VALUE)
569 internal_error ("too large function value type, needs %d registers,\
570 have only %d registers for this", nregs, MMIX_MAX_REGS_FOR_VALUE);
572 /* FIXME: Maybe we should handle structure values like this too
573 (adjusted for BLKmode), perhaps for both ABI:s. */
574 for (i = 0; i < nregs - 1; i++)
575 vec[i]
576 = gen_rtx_EXPR_LIST (VOIDmode,
577 gen_rtx_REG (cmode, first_val_regnum + i),
578 GEN_INT ((i + 1) * BITS_PER_UNIT));
580 vec[nregs - 1]
581 = gen_rtx_EXPR_LIST (VOIDmode,
582 gen_rtx_REG (cmode, first_val_regnum + nregs - 1),
583 GEN_INT (0));
585 return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nregs, vec));
588 /* EH_RETURN_DATA_REGNO. */
591 mmix_eh_return_data_regno (n)
592 int n ATTRIBUTE_UNUSED;
594 if (n >= 0 && n < 4)
595 return MMIX_EH_RETURN_DATA_REGNO_START + n;
597 return INVALID_REGNUM;
600 /* EH_RETURN_STACKADJ_RTX. */
603 mmix_eh_return_stackadj_rtx ()
605 return gen_rtx_REG (Pmode, MMIX_EH_RETURN_STACKADJ_REGNUM);
608 /* EH_RETURN_HANDLER_RTX. */
611 mmix_eh_return_handler_rtx ()
613 return
614 gen_rtx_REG (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
617 /* ASM_PREFERRED_EH_DATA_FORMAT. */
620 mmix_asm_preferred_eh_data_format (code, global)
621 int code ATTRIBUTE_UNUSED;
622 int global ATTRIBUTE_UNUSED;
624 /* This is the default (was at 2001-07-20). Revisit when needed. */
625 return DW_EH_PE_absptr;
628 /* Emit the function prologue. For simplicity while the port is still
629 in a flux, we do it as text rather than the now preferred RTL way,
630 as (define_insn "function_prologue").
632 FIXME: Translate to RTL and/or optimize some of the DWARF 2 stuff. */
634 void
635 mmix_target_asm_function_prologue (stream, locals_size)
636 FILE *stream;
637 HOST_WIDE_INT locals_size;
639 int regno;
640 int stack_space_to_allocate
641 = (current_function_outgoing_args_size
642 + current_function_pretend_args_size
643 + (int) locals_size + 8 + 7) & ~7;
644 int offset = -8;
645 int empty_stack_frame
646 = (current_function_outgoing_args_size == 0
647 && locals_size == 0
648 && current_function_pretend_args_size == 0
649 && current_function_varargs == 0
650 && current_function_stdarg == 0);
651 int doing_dwarf = dwarf2out_do_frame ();
652 long cfa_offset = 0;
654 /* Guard our assumptions. Very low priority FIXME. */
655 if (locals_size != (int) locals_size)
656 error ("stack frame too big");
658 /* Add room needed to save global non-register-stack registers. */
659 for (regno = 255;
660 regno >= MMIX_FIRST_GLOBAL_REGNUM;
661 regno--)
662 /* Note that we assume that the frame-pointer-register is one of these
663 registers, in which case we don't count it here. */
664 if ((((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
665 && regs_ever_live[regno] && !call_used_regs[regno]))
666 || IS_MMIX_EH_RETURN_DATA_REG (regno))
667 stack_space_to_allocate += 8;
669 /* If we do have a frame-pointer, add room for it. */
670 if (frame_pointer_needed)
671 stack_space_to_allocate += 8;
673 /* If we have a non-local label, we need to be able to unwind to it, so
674 store the current register stack pointer. Also store the return
675 address if we do that. */
676 if (MMIX_CFUN_HAS_LANDING_PAD)
677 stack_space_to_allocate += 16;
678 else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
679 /* If we do have a saved return-address slot, add room for it. */
680 stack_space_to_allocate += 8;
682 /* Make sure we don't get an unaligned stack. */
683 if ((stack_space_to_allocate % 8) != 0)
684 internal_error ("stack frame not a multiple of 8 bytes: %d",
685 stack_space_to_allocate);
687 if (current_function_pretend_args_size)
689 int mmix_first_vararg_reg
690 = (MMIX_FIRST_INCOMING_ARG_REGNUM
691 + (MMIX_MAX_ARGS_IN_REGS
692 - current_function_pretend_args_size / 8));
694 for (regno
695 = MMIX_FIRST_INCOMING_ARG_REGNUM + MMIX_MAX_ARGS_IN_REGS - 1;
696 regno >= mmix_first_vararg_reg;
697 regno--)
699 if (offset < 0)
701 int stack_chunk
702 = stack_space_to_allocate > (256 - 8)
703 ? (256 - 8) : stack_space_to_allocate;
705 fprintf (stream, "\tSUBU %s,%s,%d\n",
706 reg_names[MMIX_STACK_POINTER_REGNUM],
707 reg_names[MMIX_STACK_POINTER_REGNUM],
708 stack_chunk);
710 if (doing_dwarf)
712 /* Each call to dwarf2out_def_cfa overrides the previous
713 setting; they don't accumulate. We must keep track
714 of the offset ourselves. */
715 cfa_offset += stack_chunk;
716 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
717 cfa_offset);
719 offset += stack_chunk;
720 stack_space_to_allocate -= stack_chunk;
723 fprintf (stream, "\tSTOU %s,%s,%d\n", reg_names[regno],
724 reg_names[MMIX_STACK_POINTER_REGNUM],
725 offset);
727 /* These registers aren't actually saved (as in "will be
728 restored"), so don't tell DWARF2 they're saved. */
730 offset -= 8;
734 /* In any case, skip over the return-address slot. FIXME: Not needed
735 now. */
736 offset -= 8;
738 /* Store the frame-pointer. */
740 if (frame_pointer_needed)
742 empty_stack_frame = 0;
744 if (offset < 0)
746 /* Get 8 less than otherwise, since we need to reach offset + 8. */
747 int stack_chunk
748 = stack_space_to_allocate > (256 - 8 - 8)
749 ? (256 - 8 - 8) : stack_space_to_allocate;
751 fprintf (stream, "\tSUBU %s,%s,%d\n",
752 reg_names[MMIX_STACK_POINTER_REGNUM],
753 reg_names[MMIX_STACK_POINTER_REGNUM],
754 stack_chunk);
755 if (doing_dwarf)
757 cfa_offset += stack_chunk;
758 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
759 cfa_offset);
761 offset += stack_chunk;
762 stack_space_to_allocate -= stack_chunk;
765 fprintf (stream, "\tSTOU %s,%s,%d\n\tADDU %s,%s,%d\n",
766 reg_names[MMIX_FRAME_POINTER_REGNUM],
767 reg_names[MMIX_STACK_POINTER_REGNUM],
768 offset,
769 reg_names[MMIX_FRAME_POINTER_REGNUM],
770 reg_names[MMIX_STACK_POINTER_REGNUM],
771 offset + 8);
772 if (doing_dwarf)
773 dwarf2out_reg_save ("", MMIX_FRAME_POINTER_REGNUM,
774 -cfa_offset + offset);
776 offset -= 8;
779 if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
781 /* Store the return-address, if one is needed on the stack. */
782 empty_stack_frame = 0;
784 if (offset < 0)
786 /* Get 8 less than otherwise, since we need to reach offset + 8. */
787 int stack_chunk
788 = stack_space_to_allocate > (256 - 8 - 8)
789 ? (256 - 8 - 8) : stack_space_to_allocate;
791 fprintf (stream, "\tSUBU %s,%s,%d\n",
792 reg_names[MMIX_STACK_POINTER_REGNUM],
793 reg_names[MMIX_STACK_POINTER_REGNUM],
794 stack_chunk);
795 if (doing_dwarf)
797 cfa_offset += stack_chunk;
798 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
799 cfa_offset);
801 offset += stack_chunk;
802 stack_space_to_allocate -= stack_chunk;
805 fprintf (stream, "\tGET $255,rJ\n\tSTOU $255,%s,%d\n",
806 reg_names[MMIX_STACK_POINTER_REGNUM],
807 offset);
808 if (doing_dwarf)
809 dwarf2out_return_save ("", -cfa_offset + offset);
810 offset -= 8;
812 else if (MMIX_CFUN_HAS_LANDING_PAD)
813 offset -= 8;
815 if (MMIX_CFUN_HAS_LANDING_PAD)
817 /* Store the register defining the numbering of local registers, so
818 we know how long to unwind the register stack. */
820 empty_stack_frame = 0;
822 if (offset < 0)
824 /* Get 8 less than otherwise, since we need to reach offset + 8. */
825 int stack_chunk
826 = stack_space_to_allocate > (256 - 8 - 8)
827 ? (256 - 8 - 8) : stack_space_to_allocate;
829 fprintf (stream, "\tSUBU %s,%s,%d\n",
830 reg_names[MMIX_STACK_POINTER_REGNUM],
831 reg_names[MMIX_STACK_POINTER_REGNUM],
832 stack_chunk);
833 offset += stack_chunk;
834 stack_space_to_allocate -= stack_chunk;
836 if (doing_dwarf)
838 cfa_offset += stack_chunk;
839 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
840 cfa_offset);
844 /* We don't tell dwarf2 about this one; we just have it to unwind
845 the register stack at landing pads. FIXME: It's a kludge because
846 we can't describe the effect of the PUSHJ and PUSHGO insns on the
847 register stack at the moment. Best thing would be to handle it
848 like stack-pointer offsets. Better: some hook into dwarf2out.c
849 to produce DW_CFA_expression:s that specify the increment of rO,
850 and unwind it at eh_return (preferred) or at the landing pad.
851 Then saves to $0..$G-1 could be specified through that register. */
853 fprintf (stream, "\tGET $255,rO\n\tSTOU $255,%s,%d\n",
854 reg_names[MMIX_STACK_POINTER_REGNUM], offset);
856 offset -= 8;
859 /* After the return-address and the frame-pointer, we have the local
860 variables. They're the ones that may have an "unaligned" size. */
861 offset -= (locals_size + 7) & ~7;
863 /* Now store all registers that are global, i.e. not saved by the
864 register file machinery.
866 It is assumed that the frame-pointer is one of these registers, so it
867 is explicitly excluded in the count. */
869 for (regno = 255;
870 regno >= MMIX_FIRST_GLOBAL_REGNUM;
871 regno--)
872 if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
873 && regs_ever_live[regno] && ! call_used_regs[regno])
874 || IS_MMIX_EH_RETURN_DATA_REG (regno))
876 empty_stack_frame = 0;
878 if (offset < 0)
880 int stack_chunk;
882 /* Since the local variables go above, we may get a large
883 offset here. */
884 if (offset < -248)
886 /* We're not going to access the locals area in the
887 prologue, so we'll just silently subtract the slab we
888 will not access. */
889 stack_chunk =
890 stack_space_to_allocate > (256 - offset - 8)
891 ? (256 - offset - 8) : stack_space_to_allocate;
893 mmix_output_register_setting (stream, 255, stack_chunk, 1);
894 fprintf (stream, "\tSUBU %s,%s,$255\n",
895 reg_names[MMIX_STACK_POINTER_REGNUM],
896 reg_names[MMIX_STACK_POINTER_REGNUM]);
898 if (doing_dwarf)
900 cfa_offset += stack_chunk;
901 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
902 cfa_offset);
905 else
907 stack_chunk = stack_space_to_allocate > (256 - 8)
908 ? (256 - 8) : stack_space_to_allocate;
910 fprintf (stream, "\tSUBU %s,%s,%d\n",
911 reg_names[MMIX_STACK_POINTER_REGNUM],
912 reg_names[MMIX_STACK_POINTER_REGNUM], stack_chunk);
913 if (doing_dwarf)
915 cfa_offset += stack_chunk;
916 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
917 cfa_offset);
921 offset += stack_chunk;
922 stack_space_to_allocate -= stack_chunk;
925 fprintf (stream, "\tSTOU %s,%s,%d\n", reg_names[regno],
926 reg_names[MMIX_STACK_POINTER_REGNUM], offset);
927 if (doing_dwarf)
928 dwarf2out_reg_save ("", regno, -cfa_offset + offset);
929 offset -= 8;
932 /* Finally, allocate room for local vars (if they weren't allocated for
933 above) and outgoing args. This might be any number of bytes (well,
934 we assume it fits in a host-int).
935 Don't allocate (the return-address slot) if the stack frame is empty. */
936 if (stack_space_to_allocate && ! empty_stack_frame)
938 if (stack_space_to_allocate < 256)
940 fprintf (stream, "\tSUBU %s,%s,%d\n",
941 reg_names[MMIX_STACK_POINTER_REGNUM],
942 reg_names[MMIX_STACK_POINTER_REGNUM],
943 stack_space_to_allocate);
945 else
947 mmix_output_register_setting (stream, 255,
948 stack_space_to_allocate, 1);
949 fprintf (stream, "\tSUBU %s,%s,$255\n",
950 reg_names[MMIX_STACK_POINTER_REGNUM],
951 reg_names[MMIX_STACK_POINTER_REGNUM]);
954 if (doing_dwarf)
956 cfa_offset += stack_space_to_allocate;
957 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
958 cfa_offset);
962 /* We put the number of the highest saved register-file register in a
963 location convenient for the call-patterns to output. Note that we
964 don't tell dwarf2 about these registers, since it can't restore them
965 anyway. */
966 for (regno = MMIX_LAST_REGISTER_FILE_REGNUM;
967 regno >= 0;
968 regno--)
969 if ((regs_ever_live[regno] && !call_used_regs[regno])
970 || (regno == MMIX_FRAME_POINTER_REGNUM && frame_pointer_needed))
971 break;
973 mmix_highest_saved_stack_register = regno;
975 /* FIXME: A kludge for the MMIXware ABI. The return value comes back in
976 L of the caller, not just the register number of the X field of
977 PUSH{J,GO}. So we need to make L agree with that number if there's a
978 function call in this function that returns a value but takes no
979 parameters (if there were parameters, L would be set to at least the
980 first parameter register, $16). A real solution includes a pass to
981 test that settings of $15 (MMIX_RETURN_VALUE_REGNUM for the MMIXware
982 ABI) dominate all function calls that return a value. This could be
983 done in the planned machine_dep_reorg pass to rename all registers. */
984 if (! TARGET_ABI_GNU && cfun->machine->has_call_value_without_parameters)
985 fprintf (stream, "\tSET %s,%s\n",
986 reg_names[MMIX_RETURN_VALUE_REGNUM],
987 reg_names[MMIX_RETURN_VALUE_REGNUM]);
990 /* TARGET_ASM_FUNCTION_EPILOGUE. */
992 void
993 mmix_target_asm_function_epilogue (stream, locals_size)
994 FILE *stream;
995 HOST_WIDE_INT locals_size;
998 int regno;
999 int stack_space_to_deallocate
1000 = (current_function_outgoing_args_size
1001 + current_function_pretend_args_size
1002 + (int) locals_size + 8 + 7) & ~7;
1004 /* The assumption that locals_size fits in an int is asserted in
1005 mmix_target_asm_function_prologue. */
1007 /* The first address to access is beyond the outgoing_args area. */
1008 int offset = current_function_outgoing_args_size;
1009 int empty_stack_frame
1010 = (current_function_outgoing_args_size == 0
1011 && locals_size == 0
1012 && current_function_pretend_args_size == 0
1013 && ! MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS
1014 && ! MMIX_CFUN_HAS_LANDING_PAD);
1016 /* Add the space for global non-register-stack registers.
1017 It is assumed that the frame-pointer register can be one of these
1018 registers, in which case it is excluded from the count when needed. */
1019 for (regno = 255;
1020 regno >= MMIX_FIRST_GLOBAL_REGNUM;
1021 regno--)
1022 if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
1023 && regs_ever_live[regno] && !call_used_regs[regno])
1024 || IS_MMIX_EH_RETURN_DATA_REG (regno))
1025 stack_space_to_deallocate += 8;
1027 /* Add in the space for register stack-pointer. If so, always add room
1028 for the saved PC. */
1029 if (MMIX_CFUN_HAS_LANDING_PAD)
1030 stack_space_to_deallocate += 16;
1031 else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
1032 /* If we have a saved return-address slot, add it in. */
1033 stack_space_to_deallocate += 8;
1035 /* Add in the frame-pointer. */
1036 if (frame_pointer_needed)
1037 stack_space_to_deallocate += 8;
1039 /* Make sure we don't get an unaligned stack. */
1040 if ((stack_space_to_deallocate % 8) != 0)
1041 internal_error ("stack frame not a multiple of octabyte: %d",
1042 stack_space_to_deallocate);
1044 /* We will add back small offsets to the stack pointer as we go.
1045 First, we restore all registers that are global, i.e. not saved by
1046 the register file machinery. */
1048 for (regno = MMIX_FIRST_GLOBAL_REGNUM;
1049 regno <= 255;
1050 regno++)
1051 if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
1052 && regs_ever_live[regno] && !call_used_regs[regno])
1053 || IS_MMIX_EH_RETURN_DATA_REG (regno))
1055 empty_stack_frame = 0;
1057 if (offset > 255)
1059 if (offset > 65535)
1061 /* There's better support for incrementing than
1062 decrementing, so we might be able to optimize this as
1063 we see a need. */
1064 mmix_output_register_setting (stream, 255, offset, 1);
1065 fprintf (stream, "\tADDU %s,%s,$255\n",
1066 reg_names[MMIX_STACK_POINTER_REGNUM],
1067 reg_names[MMIX_STACK_POINTER_REGNUM]);
1069 else
1070 fprintf (stream, "\tINCL %s,%d\n",
1071 reg_names[MMIX_STACK_POINTER_REGNUM], offset);
1073 stack_space_to_deallocate -= offset;
1074 offset = 0;
1077 fprintf (stream, "\tLDOU %s,%s,%d\n",
1078 reg_names[regno],
1079 reg_names[MMIX_STACK_POINTER_REGNUM],
1080 offset);
1081 offset += 8;
1084 /* Here is where the local variables were. As in the prologue, they
1085 might be of an unaligned size. */
1086 offset += (locals_size + 7) & ~7;
1089 /* The saved register stack pointer is just below the frame-pointer
1090 register. We don't need to restore it "manually"; the POP
1091 instruction does that. */
1092 if (MMIX_CFUN_HAS_LANDING_PAD)
1093 offset += 16;
1094 else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
1095 /* The return-address slot is just below the frame-pointer register.
1096 We don't need to restore it because we don't really use it. */
1097 offset += 8;
1099 /* Get back the old frame-pointer-value. */
1100 if (frame_pointer_needed)
1102 empty_stack_frame = 0;
1104 if (offset > 255)
1106 if (offset > 65535)
1108 /* There's better support for incrementing than
1109 decrementing, so we might be able to optimize this as
1110 we see a need. */
1111 mmix_output_register_setting (stream, 255, offset, 1);
1112 fprintf (stream, "\tADDU %s,%s,$255\n",
1113 reg_names[MMIX_STACK_POINTER_REGNUM],
1114 reg_names[MMIX_STACK_POINTER_REGNUM]);
1116 else
1117 fprintf (stream, "\tINCL %s,%d\n",
1118 reg_names[MMIX_STACK_POINTER_REGNUM], offset);
1120 stack_space_to_deallocate -= offset;
1121 offset = 0;
1124 fprintf (stream, "\tLDOU %s,%s,%d\n",
1125 reg_names[MMIX_FRAME_POINTER_REGNUM],
1126 reg_names[MMIX_STACK_POINTER_REGNUM],
1127 offset);
1128 offset += 8;
1131 /* Do not deallocate the return-address slot if the stack frame is
1132 empty, because then it was never allocated. */
1133 if (! empty_stack_frame)
1135 /* We do not need to restore pretended incoming args, just add
1136 back offset to sp. */
1137 if (stack_space_to_deallocate > 65535)
1139 /* There's better support for incrementing than decrementing, so
1140 we might be able to optimize this as we see a need. */
1141 mmix_output_register_setting (stream, 255,
1142 stack_space_to_deallocate, 1);
1143 fprintf (stream, "\tADDU %s,%s,$255\n",
1144 reg_names[MMIX_STACK_POINTER_REGNUM],
1145 reg_names[MMIX_STACK_POINTER_REGNUM]);
1147 else
1148 fprintf (stream, "\tINCL %s,%d\n",
1149 reg_names[MMIX_STACK_POINTER_REGNUM],
1150 stack_space_to_deallocate);
1153 if (current_function_calls_eh_return)
1154 /* Adjustment the (normal) stack-pointer to that of the receiver.
1155 FIXME: It would be nice if we could also adjust the register stack
1156 here, but we need to express it through DWARF 2 too. */
1157 fprintf (stream, "\tADDU %s,%s,%s\n",
1158 reg_names [MMIX_STACK_POINTER_REGNUM],
1159 reg_names [MMIX_STACK_POINTER_REGNUM],
1160 reg_names [MMIX_EH_RETURN_STACKADJ_REGNUM]);
1162 /* The extra \n is so we have a blank line between the assembly code of
1163 separate functions. */
1164 fprintf (stream, "\tPOP %d,0\n\n",
1165 (! TARGET_ABI_GNU
1166 && current_function_return_rtx != NULL
1167 && ! current_function_returns_struct)
1168 ? (GET_CODE (current_function_return_rtx) == PARALLEL
1169 ? GET_NUM_ELEM (XVEC (current_function_return_rtx, 0)) : 1)
1170 : 0);
1173 /* ASM_OUTPUT_MI_THUNK. */
1175 void
1176 mmix_asm_output_mi_thunk (stream, fndecl, delta, func)
1177 FILE * stream;
1178 tree fndecl ATTRIBUTE_UNUSED;
1179 int delta;
1180 tree func;
1182 /* If you define STRUCT_VALUE to 0, rather than use STRUCT_VALUE_REGNUM,
1183 (i.e. pass location of structure to return as invisible first
1184 argument) you need to tweak this code too. */
1185 const char *regname = reg_names[MMIX_FIRST_INCOMING_ARG_REGNUM];
1187 if (delta >= 0 && delta < 65536)
1188 asm_fprintf (stream, "\tINCL %s,%d\n", delta, regname);
1189 else if (delta < 0 && delta >= -255)
1190 asm_fprintf (stream, "\tSUBU %s,%s,%d\n", regname, regname, -delta);
1191 else
1193 mmix_output_register_setting (stream, 255, delta, 1);
1194 asm_fprintf (stream, "\tADDU %s,%s,$255\n", regname, regname);
1197 fprintf (stream, "\tJMP ");
1198 assemble_name (stream, XSTR (XEXP (DECL_RTL (func), 0), 0));
1199 fprintf (stream, "\n");
1202 /* FUNCTION_PROFILER. */
1204 void
1205 mmix_function_profiler (stream, labelno)
1206 FILE *stream ATTRIBUTE_UNUSED;
1207 int labelno ATTRIBUTE_UNUSED;
1209 sorry ("function_profiler support for MMIX");
1212 /* SETUP_INCOMING_VARARGS. */
1214 void
1215 mmix_setup_incoming_varargs (args_so_farp, mode, vartype, pretend_sizep,
1216 second_time)
1217 CUMULATIVE_ARGS * args_so_farp;
1218 enum machine_mode mode;
1219 tree vartype;
1220 int * pretend_sizep;
1221 int second_time ATTRIBUTE_UNUSED;
1223 /* For stdarg, the last named variable has been handled, but
1224 args_so_farp has not been advanced for it. For varargs, the current
1225 argument is to be counted to the anonymous ones. */
1226 if (current_function_stdarg)
1228 if (args_so_farp->regs + 1 < MMIX_MAX_ARGS_IN_REGS)
1229 *pretend_sizep
1230 = (MMIX_MAX_ARGS_IN_REGS - (args_so_farp->regs + 1)) * 8;
1232 else if (current_function_varargs)
1234 if (args_so_farp->regs < MMIX_MAX_ARGS_IN_REGS)
1235 *pretend_sizep
1236 = (MMIX_MAX_ARGS_IN_REGS - args_so_farp->regs) * 8;
1238 /* For varargs, we get here when we see the last named parameter,
1239 which will actually be passed on stack. So make the next call
1240 (there will be one) to FUNCTION_ARG return 0, to count it on
1241 stack, so va_arg for it will get right. FIXME: The GCC core
1242 should provide TRT. */
1243 args_so_farp->now_varargs = 1;
1245 else
1246 internal_error ("neither varargs or stdarg in mmix_setup_incoming_varargs");
1249 /* We assume that one argument takes up one register here. That should
1250 be true until we start messing with multi-reg parameters. */
1251 if ((7 + (MMIX_FUNCTION_ARG_SIZE (mode, vartype))) / 8 != 1)
1252 internal_error ("MMIX Internal: Last named vararg would not fit in a register");
1255 /* EXPAND_BUILTIN_VA_ARG. */
1257 /* This is modified from the "standard" implementation of va_arg: read the
1258 value from the current (padded) address and increment by the (padded)
1259 size. The difference for MMIX is that if the type is
1260 pass-by-reference, then perform an indirection. */
1263 mmix_expand_builtin_va_arg (valist, type)
1264 tree valist;
1265 tree type;
1267 tree addr_tree, t;
1268 HOST_WIDE_INT align;
1269 HOST_WIDE_INT rounded_size;
1270 rtx addr;
1272 /* Compute the rounded size of the type. */
1273 align = PARM_BOUNDARY / BITS_PER_UNIT;
1274 rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
1276 /* Get AP. */
1277 addr_tree = valist;
1279 if (AGGREGATE_TYPE_P (type)
1280 && GET_MODE_UNIT_SIZE (TYPE_MODE (type)) < 8
1281 && GET_MODE_UNIT_SIZE (TYPE_MODE (type)) != 0)
1283 /* Adjust for big-endian the location of aggregates passed in a
1284 register, but where the aggregate is accessed in a shorter mode
1285 than the natural register mode (i.e. it is accessed as SFmode(?),
1286 SImode, HImode or QImode rather than DImode or DFmode(?)). FIXME:
1287 Or should we adjust the mode in which the aggregate is read, to be
1288 a register size mode? (Hum, nah, a small offset is generally
1289 cheaper than a wider memory access on MMIX.) */
1290 addr_tree
1291 = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
1292 build_int_2 ((BITS_PER_WORD / BITS_PER_UNIT)
1293 - GET_MODE_UNIT_SIZE (TYPE_MODE (type)), 0));
1295 else
1297 HOST_WIDE_INT adj;
1298 adj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT;
1299 if (rounded_size > align)
1300 adj = rounded_size;
1302 addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
1303 build_int_2 (rounded_size - adj, 0));
1305 /* If this type is larger than what fits in a register, then it is
1306 passed by reference. */
1307 if (rounded_size > BITS_PER_WORD / BITS_PER_UNIT)
1309 tree type_ptr = build_pointer_type (type);
1310 addr_tree = build1 (INDIRECT_REF, type_ptr, addr_tree);
1314 addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
1315 addr = copy_to_reg (addr);
1317 /* Compute new value for AP. For MMIX, it is always advanced by the
1318 size of a register. */
1319 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1320 build (PLUS_EXPR, TREE_TYPE (valist), valist,
1321 build_int_2 (BITS_PER_WORD / BITS_PER_UNIT, 0)));
1322 TREE_SIDE_EFFECTS (t) = 1;
1323 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1325 return addr;
1328 /* TRAMPOLINE_SIZE. */
1329 /* Four 4-byte insns plus two 8-byte values. */
1330 int mmix_trampoline_size = 32;
1333 /* TRAMPOLINE_TEMPLATE. */
1335 void
1336 mmix_trampoline_template (stream)
1337 FILE * stream;
1339 /* Read a value from to static-chain, jump somewhere. The static chain
1340 is stored at offset 16, and the function address is stored at offset
1341 24. */
1342 /* FIXME: GCC copies this using *intsize* (tetra), when it should use
1343 register size (octa). */
1344 fprintf (stream, "\tGETA $255,1F\n\t");
1345 fprintf (stream, "LDOU %s,$255,0\n\t",
1346 reg_names[MMIX_STATIC_CHAIN_REGNUM]);
1347 fprintf (stream, "LDOU $255,$255,8\n\t");
1348 fprintf (stream, "GO $255,$255,0\n");
1349 fprintf (stream, "1H\tOCTA 0\n\t");
1350 fprintf (stream, "OCTA 0\n");
1353 /* INITIALIZE_TRAMPOLINE. */
1354 /* Set the static chain and function pointer field in the trampoline.
1355 We also SYNCID here to be sure (doesn't matter in the simulator, but
1356 some day it will). */
1358 void
1359 mmix_initialize_trampoline (trampaddr, fnaddr, static_chain)
1360 rtx trampaddr;
1361 rtx fnaddr;
1362 rtx static_chain;
1364 emit_move_insn (gen_rtx_MEM (DImode, plus_constant (trampaddr, 16)),
1365 static_chain);
1366 emit_move_insn (gen_rtx_MEM (DImode,
1367 plus_constant (trampaddr, 24)),
1368 fnaddr);
1369 emit_insn (gen_sync_icache (validize_mem (gen_rtx_MEM (DImode,
1370 trampaddr)),
1371 GEN_INT (mmix_trampoline_size - 1)));
1374 /* We must exclude constant addresses that have an increment that is not a
1375 multiple of four bytes because of restrictions of the GETA
1376 instruction. FIXME: No, I don't think so. Just add a constraint. */
1379 mmix_constant_address_p (x)
1380 rtx x;
1382 RTX_CODE code = GET_CODE (x);
1383 int addend = 0;
1385 if (code == LABEL_REF || code == SYMBOL_REF)
1386 return 1;
1388 if (code == CONSTANT_P_RTX || code == HIGH)
1389 /* FIXME: Don't know how to dissect these. Avoid them for now. */
1390 return 0;
1392 switch (code)
1394 case LABEL_REF:
1395 case SYMBOL_REF:
1396 return 1;
1398 case PLUS:
1399 /* Can we get a naked PLUS? */
1400 case CONSTANT_P_RTX:
1401 case HIGH:
1402 /* FIXME: Don't know how to dissect these. Avoid them for now. */
1403 return 0;
1405 case CONST_INT:
1406 addend = INTVAL (x);
1407 break;
1409 case CONST_DOUBLE:
1410 if (GET_MODE (x) != VOIDmode)
1411 /* Strange that we got here. FIXME: Check if we do. */
1412 return 0;
1413 addend = CONST_DOUBLE_LOW (x);
1414 break;
1416 case CONST:
1417 /* Note that expressions with arithmetic on forward references don't
1418 work in mmixal. People using gcc assembly code with mmixal might
1419 need to move arrays and such to before the point of use. */
1420 if (GET_CODE (XEXP (x, 0)) == PLUS)
1422 rtx x0 = XEXP (XEXP (x, 0), 0);
1423 rtx x1 = XEXP (XEXP (x, 0), 1);
1425 if ((GET_CODE (x0) == SYMBOL_REF
1426 || GET_CODE (x0) == LABEL_REF)
1427 && (GET_CODE (x1) == CONST_INT
1428 || (GET_CODE (x1) == CONST_DOUBLE
1429 && GET_MODE (x1) == VOIDmode)))
1430 addend = mmix_intval (x1);
1431 else
1432 return 0;
1434 else
1435 return 0;
1436 break;
1438 default:
1439 return 0;
1442 return (addend & 3) == 0;
1445 /* Return 1 if the address is OK, otherwise 0.
1446 Used by GO_IF_LEGITIMATE_ADDRESS. */
1449 mmix_legitimate_address (mode, x, strict_checking)
1450 enum machine_mode mode ATTRIBUTE_UNUSED;
1451 rtx x;
1452 int strict_checking;
1454 #define MMIX_REG_OK(X) \
1455 ((strict_checking \
1456 && (REGNO (X) <= MMIX_LAST_GENERAL_REGISTER \
1457 || (reg_renumber[REGNO (X)] > 0 \
1458 && reg_renumber[REGNO (X)] <= MMIX_LAST_GENERAL_REGISTER))) \
1459 || (!strict_checking \
1460 && (REGNO (X) <= MMIX_LAST_GENERAL_REGISTER \
1461 || REGNO (X) >= FIRST_PSEUDO_REGISTER \
1462 || REGNO (X) == ARG_POINTER_REGNUM)))
1464 /* We only accept:
1465 (mem reg)
1466 (mem (plus reg reg))
1467 (mem (plus reg 0..255)). */
1470 /* (mem reg) */
1471 if (REG_P (x) && MMIX_REG_OK (x))
1472 return 1;
1474 if (GET_CODE(x) == PLUS)
1476 rtx x1 = XEXP (x, 0);
1477 rtx x2 = XEXP (x, 1);
1479 /* Try swapping the order. FIXME: Do we need this? */
1480 if (! REG_P (x1))
1482 rtx tem = x1;
1483 x1 = x2;
1484 x2 = tem;
1487 /* (mem (plus (reg) (?))) */
1488 if (!REG_P (x1) || !MMIX_REG_OK (x1))
1489 return 0;
1491 /* (mem (plus (reg) (reg))) */
1492 if (REG_P (x2) && MMIX_REG_OK (x2))
1493 return 1;
1495 /* (mem (plus (reg) (0..255))) */
1496 if (GET_CODE (x2) == CONST_INT
1497 && CONST_OK_FOR_LETTER_P (INTVAL (x2), 'I'))
1498 return 1;
1501 return 0;
1504 /* LEGITIMATE_CONSTANT_P. */
1507 mmix_legitimate_constant_p (x)
1508 rtx x;
1510 RTX_CODE code = GET_CODE (x);
1512 /* We must allow any number due to the way the cse passes works; if we
1513 do not allow any number here, general_operand will fail, and insns
1514 will fatally fail recognition instead of "softly". */
1515 if (code == CONST_INT || code == CONST_DOUBLE)
1516 return 1;
1518 return CONSTANT_ADDRESS_P (x);
1521 /* SELECT_CC_MODE. */
1523 enum machine_mode
1524 mmix_select_cc_mode (op, x, y)
1525 RTX_CODE op;
1526 rtx x;
1527 rtx y ATTRIBUTE_UNUSED;
1529 /* We use CCmode, CC_UNSmode, CC_FPmode, CC_FPEQmode and CC_FUNmode to
1530 output different compare insns. Note that we do not check the
1531 validity of the comparison here. */
1533 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1535 if (op == ORDERED || op == UNORDERED || op == UNGE
1536 || op == UNGT || op == UNLE || op == UNLT)
1537 return CC_FUNmode;
1539 if (op == EQ || op == NE)
1540 return CC_FPEQmode;
1542 return CC_FPmode;
1545 if (op == GTU || op == LTU || op == GEU || op == LEU)
1546 return CC_UNSmode;
1548 return CCmode;
1551 /* CANONICALIZE_COMPARISON.
1552 FIXME: Check if the number adjustments trig. */
1554 void
1555 mmix_canonicalize_comparison (codep, op0p, op1p)
1556 RTX_CODE * codep;
1557 rtx * op0p ATTRIBUTE_UNUSED;
1558 rtx * op1p;
1560 /* Change -1 to zero, if possible. */
1561 if ((*codep == LE || *codep == GT)
1562 && GET_CODE (*op1p) == CONST_INT
1563 && *op1p == constm1_rtx)
1565 *codep = *codep == LE ? LT : GE;
1566 *op1p = const0_rtx;
1569 /* Fix up 256 to 255, if possible. */
1570 if ((*codep == LT || *codep == LTU || *codep == GE || *codep == GEU)
1571 && GET_CODE (*op1p) == CONST_INT
1572 && INTVAL (*op1p) == 256)
1574 /* FIXME: Remove when I know this trigs. */
1575 fatal_insn ("oops, not debugged; fixing up value:", *op1p);
1576 *codep = *codep == LT ? LE : *codep == LTU ? LEU : *codep
1577 == GE ? GT : GTU;
1578 *op1p = GEN_INT (255);
1582 /* REVERSIBLE_CC_MODE. */
1585 mmix_reversible_cc_mode (mode)
1586 enum machine_mode mode;
1588 /* That is, all integer and the EQ, NE, ORDERED and UNORDERED float
1589 cmpares. */
1590 return mode != CC_FPmode;
1593 /* DEFAULT_RTX_COSTS. */
1596 mmix_rtx_cost_recalculated (x, code, outer_code, costp)
1597 rtx x ATTRIBUTE_UNUSED;
1598 RTX_CODE code ATTRIBUTE_UNUSED;
1599 RTX_CODE outer_code ATTRIBUTE_UNUSED;
1600 int *costp ATTRIBUTE_UNUSED;
1602 /* For the time being, this is just a stub and we'll accept the
1603 generic calculations, until we can do measurements, at least.
1604 Say we did not modify any calculated costs. */
1605 return 0;
1608 /* ADDRESS_COST. */
1611 mmix_address_cost (addr)
1612 rtx addr ATTRIBUTE_UNUSED;
1614 /* There's no difference in the address costs and we have lots of
1615 registers. Some targets use constant 0, many others use 1 to say
1616 this. Let's start with 1. */
1617 return 1;
1620 /* REGISTER_MOVE_COST. */
1623 mmix_register_move_cost (mode, from, to)
1624 enum machine_mode mode ATTRIBUTE_UNUSED;
1625 enum reg_class from;
1626 enum reg_class to;
1628 return (from == GENERAL_REGS && from == to) ? 2 : 3;
1631 /* Note that we don't have a TEXT_SECTION_ASM_OP, because it has to be a
1632 compile-time constant; it's used in an asm in crtstuff.c, compiled for
1633 the target. */
1635 /* DATA_SECTION_ASM_OP. */
1637 const char *
1638 mmix_data_section_asm_op ()
1640 return "\t.data ! mmixal:= 8H LOC 9B";
1643 /* SELECT_SECTION.
1644 The meat is from elfos.h, which we will eventually consider using. */
1646 void
1647 mmix_select_section (decl, reloc, align)
1648 tree decl;
1649 int reloc;
1650 int align ATTRIBUTE_UNUSED;
1652 if (TREE_CODE (decl) == STRING_CST)
1654 if (! flag_writable_strings)
1655 const_section ();
1656 else
1657 data_section ();
1659 else if (TREE_CODE (decl) == VAR_DECL)
1661 if ((flag_pic && reloc)
1662 || !TREE_READONLY (decl) || TREE_SIDE_EFFECTS (decl)
1663 || !DECL_INITIAL (decl)
1664 || (DECL_INITIAL (decl) != error_mark_node
1665 && !TREE_CONSTANT (DECL_INITIAL (decl))))
1666 data_section ();
1667 else
1668 const_section ();
1670 else if (TREE_CODE (decl) == CONSTRUCTOR)
1672 if ((flag_pic && reloc)
1673 || !TREE_READONLY (decl) || TREE_SIDE_EFFECTS (decl)
1674 || ! TREE_CONSTANT (decl))
1675 data_section ();
1676 else
1677 const_section ();
1679 else
1680 const_section ();
1683 /* ENCODE_SECTION_INFO. */
1685 void
1686 mmix_encode_section_info (decl)
1687 tree decl;
1689 /* Test for an external declaration, and do nothing if it is one. */
1690 if ((TREE_CODE (decl) == VAR_DECL
1691 && (DECL_EXTERNAL (decl) || TREE_PUBLIC (decl))
1692 && ! TREE_STATIC (decl))
1693 || (TREE_CODE (decl) == FUNCTION_DECL
1694 && (DECL_EXTERNAL (decl) || TREE_PUBLIC (decl))))
1696 else if (DECL_P (decl))
1698 /* For non-visible declarations, add a "@" prefix, which we skip
1699 when the label is output. If the label does not have this
1700 prefix, a ":" is output.
1702 Note that this does not work for data that is declared extern and
1703 later defined as static. If there's code in between, that code
1704 will refer to the extern declaration. And vice versa. Until we
1705 can get rid of mmixal, we have to assume that code is well-behaved
1706 or come up with a contorted scheme to work around bad code. */
1708 const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
1709 int len = strlen (str);
1710 char *newstr;
1712 /* Doing as rs6000 seems safe; always use ggc. Except don't copy
1713 the suspected off-by-one bug.
1714 FIXME: Is it still there? yes 2001-08-23
1715 Why is the return type of ggc_alloc_string const? */
1716 newstr = (char *) ggc_alloc_string ("", len + 2);
1718 strcpy (newstr + 1, str);
1719 *newstr = '@';
1720 XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
1723 /* FIXME: Later on, add SYMBOL_REF_FLAG for things that we can reach
1724 from here via GETA, to check in LEGITIMATE_CONSTANT_P. Needs to have
1725 different options for the cases where we want *all* to be assumed
1726 reachable via GETA, or all constant symbols, or just text symbols in
1727 this file, or perhaps just the constant pool. */
1730 /* STRIP_NAME_ENCODING. */
1732 const char *
1733 mmix_strip_name_encoding (name)
1734 const char *name;
1736 for (; (*name == '@' || *name == '*'); name++)
1739 return name;
1742 /* UNIQUE_SECTION.
1743 The meat is from elfos.h, which we should consider using. */
1745 void
1746 mmix_unique_section (decl, reloc)
1747 tree decl;
1748 int reloc;
1750 int len;
1751 int sec;
1752 const char *name;
1753 char *string;
1754 const char *prefix;
1755 static const char *const prefixes[4][2] =
1757 { ".text.", ".gnu.linkonce.t." },
1758 { ".rodata.", ".gnu.linkonce.r." },
1759 { ".data.", ".gnu.linkonce.d." },
1760 { ".bss.", ".gnu.linkonce.b." }
1763 if (TREE_CODE (decl) == FUNCTION_DECL)
1764 sec = 0;
1765 else if (DECL_INITIAL (decl) == 0
1766 || DECL_INITIAL (decl) == error_mark_node)
1767 sec = 3;
1768 else if (DECL_READONLY_SECTION (decl, reloc))
1769 sec = 1;
1770 else
1771 sec = 2;
1773 name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
1774 /* Strip off any encoding in name. */
1775 STRIP_NAME_ENCODING (name, name);
1776 prefix = prefixes[sec][DECL_ONE_ONLY (decl)];
1777 len = strlen (name) + strlen (prefix);
1778 string = alloca (len + 1);
1780 sprintf (string, "%s%s", prefix, name);
1782 DECL_SECTION_NAME (decl) = build_string (len, string);
1785 /* ASM_FILE_START. */
1787 void
1788 mmix_asm_file_start (stream)
1789 FILE * stream;
1791 /* We just emit a little comment for the time being. FIXME: Perhaps add
1792 -mstandalone and some segment and prefix setup here. */
1793 ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename);
1795 fprintf (stream, "! mmixal:= 8H LOC Data_Section\n");
1797 /* Make sure each file starts with the text section. */
1798 text_section ();
1801 /* ASM_FILE_END. */
1803 void
1804 mmix_asm_file_end (stream)
1805 FILE * stream ATTRIBUTE_UNUSED;
1807 /* Make sure each file ends with the data section. */
1808 data_section ();
1811 /* ASM_IDENTIFY_GCC. */
1813 void
1814 mmix_asm_identify_gcc (stream)
1815 FILE * stream;
1817 /* No real need for the time being. May be useful to GDB later on. */
1818 fprintf (stream, "# Compiled by GCC version %s\n",
1819 version_string);
1822 /* ASM_OUTPUT_SOURCE_FILENAME. */
1824 void
1825 mmix_asm_output_source_filename (stream, name)
1826 FILE * stream;
1827 const char * name;
1829 fprintf (stream, "# 1 ");
1830 OUTPUT_QUOTED_STRING (stream, name);
1831 fprintf (stream, "\n");
1834 /* OUTPUT_QUOTED_STRING. */
1836 void
1837 mmix_output_quoted_string (stream, string, length)
1838 FILE * stream;
1839 const char * string;
1840 int length;
1842 const char * string_end = string + length;
1843 static const char *const unwanted_chars = "\"[]\\";
1845 /* Output "any character except newline and double quote character". We
1846 play it safe and avoid all control characters too. We also do not
1847 want [] as characters, should input be passed through m4 with [] as
1848 quotes. Further, we avoid "\", because the GAS port handles it as a
1849 quoting character. */
1850 while (string < string_end)
1852 if (*string
1853 && (unsigned char) *string < 128
1854 && !ISCNTRL (*string)
1855 && strchr (unwanted_chars, *string) == NULL)
1857 fputc ('"', stream);
1858 while (*string
1859 && (unsigned char) *string < 128
1860 && !ISCNTRL (*string)
1861 && strchr (unwanted_chars, *string) == NULL
1862 && string < string_end)
1864 fputc (*string, stream);
1865 string++;
1867 fputc ('"', stream);
1868 if (string < string_end)
1869 fprintf (stream, ",");
1871 if (string < string_end)
1873 fprintf (stream, "#%x", *string & 255);
1874 string++;
1875 if (string < string_end)
1876 fprintf (stream, ",");
1881 /* ASM_OUTPUT_SOURCE_LINE. */
1883 void
1884 mmix_asm_output_source_line (stream, lineno)
1885 FILE * stream;
1886 int lineno;
1888 fprintf (stream, "# %d ", lineno);
1889 OUTPUT_QUOTED_STRING (stream, main_input_filename);
1890 fprintf (stream, "\n");
1893 /* Target hook for assembling integer objects. Use mmix_print_operand
1894 for WYDE and TETRA. Use mmix_output_octa to output 8-byte
1895 CONST_DOUBLEs. */
1897 static bool
1898 mmix_assemble_integer (x, size, aligned_p)
1899 rtx x;
1900 unsigned int size;
1901 int aligned_p;
1903 if (aligned_p)
1904 switch (size)
1906 case 1:
1907 fputs ("\tBYTE\t", asm_out_file);
1908 mmix_print_operand (asm_out_file, x, 'B');
1909 fputc ('\n', asm_out_file);
1910 return true;
1912 case 2:
1913 fputs ("\tWYDE\t", asm_out_file);
1914 mmix_print_operand (asm_out_file, x, 'W');
1915 fputc ('\n', asm_out_file);
1916 return true;
1918 case 4:
1919 fputs ("\tTETRA\t", asm_out_file);
1920 mmix_print_operand (asm_out_file, x, 'L');
1921 fputc ('\n', asm_out_file);
1922 return true;
1924 case 8:
1925 if (GET_CODE (x) == CONST_DOUBLE)
1926 mmix_output_octa (asm_out_file, mmix_intval (x), 0);
1927 else
1928 assemble_integer_with_op ("\tOCTA\t", x);
1929 return true;
1931 return default_assemble_integer (x, size, aligned_p);
1934 /* ASM_OUTPUT_ASCII. */
1936 void
1937 mmix_asm_output_ascii (stream, string, length)
1938 FILE *stream;
1939 const char *string;
1940 int length;
1942 while (length > 0)
1944 int chunk_size = length > 60 ? 60 : length;
1945 fprintf (stream, "\tBYTE ");
1946 mmix_output_quoted_string (stream, string, chunk_size);
1947 string += chunk_size;
1948 length -= chunk_size;
1949 fprintf (stream, "\n");
1953 /* ASM_OUTPUT_ALIGNED_COMMON. */
1955 void
1956 mmix_asm_output_aligned_common (stream, name, size, align)
1957 FILE *stream;
1958 const char *name;
1959 int size;
1960 int align;
1962 /* This is mostly the elfos.h one. There doesn't seem to be a way to
1963 express this in a mmixal-compatible way. */
1964 fprintf (stream, "\t.comm\t");
1965 assemble_name (stream, name);
1966 fprintf (stream, ",%u,%u ! mmixal-incompatible COMMON\n",
1967 size, align / BITS_PER_UNIT);
1970 /* ASM_OUTPUT_ALIGNED_LOCAL. */
1972 void
1973 mmix_asm_output_aligned_local (stream, name, size, align)
1974 FILE * stream;
1975 const char * name;
1976 int size;
1977 int align;
1979 data_section ();
1981 ASM_OUTPUT_ALIGN (stream, exact_log2 (align/BITS_PER_UNIT));
1982 assemble_name (stream, name);
1983 fprintf (stream, "\tLOC @+%d\n", size);
1986 /* ASM_OUTPUT_LABEL. */
1988 void
1989 mmix_asm_output_label (stream, name)
1990 FILE *stream;
1991 const char * name;
1993 assemble_name (stream, name);
1994 fprintf (stream, "\tIS @\n");
1997 /* ASM_DECLARE_REGISTER_GLOBAL. */
1999 void
2000 mmix_asm_declare_register_global (stream, decl, regno, name)
2001 FILE *stream ATTRIBUTE_UNUSED;
2002 tree decl ATTRIBUTE_UNUSED;
2003 int regno ATTRIBUTE_UNUSED;
2004 const char *name ATTRIBUTE_UNUSED;
2006 /* Nothing to do here, but there *will* be, therefore the framework is
2007 here. */
2010 /* ASM_GLOBALIZE_LABEL. */
2012 void
2013 mmix_asm_globalize_label (stream, name)
2014 FILE * stream ATTRIBUTE_UNUSED;
2015 const char * name ATTRIBUTE_UNUSED;
2017 asm_fprintf (stream, "\t.global ");
2018 assemble_name (stream, name);
2019 putc ('\n', stream);
2022 /* ASM_WEAKEN_LABEL. */
2024 void
2025 mmix_asm_weaken_label (stream, name)
2026 FILE * stream ATTRIBUTE_UNUSED;
2027 const char * name ATTRIBUTE_UNUSED;
2029 asm_fprintf (stream, "\t.weak ");
2030 assemble_name (stream, name);
2031 asm_fprintf (stream, " ! mmixal-incompatible\n");
2034 /* MAKE_DECL_ONE_ONLY. */
2036 void
2037 mmix_make_decl_one_only (decl)
2038 tree decl;
2040 DECL_WEAK (decl) = 1;
2043 /* ASM_OUTPUT_LABELREF.
2044 Strip GCC's '*' and our own '@'. No order is assumed. */
2046 void
2047 mmix_asm_output_labelref (stream, name)
2048 FILE *stream;
2049 const char *name;
2051 int is_extern = 0;
2053 for (; (*name == '@' || *name == '*'); name++)
2054 if (*name == '@')
2055 is_extern = 1;
2057 asm_fprintf (stream, "%s%U%s",
2058 is_extern && TARGET_TOPLEVEL_SYMBOLS ? ":" : "",
2059 name);
2062 /* ASM_OUTPUT_INTERNAL_LABEL. */
2064 void
2065 mmix_asm_output_internal_label (stream, name, num)
2066 FILE * stream;
2067 const char * name;
2068 int num;
2070 fprintf (stream, "%s:%d\tIS @\n", name, num);
2073 /* ASM_OUTPUT_DEF. */
2075 void
2076 mmix_asm_output_def (stream, name, value)
2077 FILE * stream;
2078 const char * name;
2079 const char * value;
2081 assemble_name (stream, name);
2082 fprintf (stream, "\tIS ");
2083 assemble_name (stream, value);
2084 fputc ('\n', stream);
2087 /* ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL. */
2089 void
2090 mmix_asm_output_define_label_difference_symbol (stream, symbol, hi, lo)
2091 FILE *stream;
2092 const char *symbol;
2093 const char *hi;
2094 const char *lo;
2096 assemble_name (stream, symbol);
2097 fprintf (stream, "\tIS\t");
2098 assemble_name (stream, hi);
2099 fputc ('-', stream);
2100 assemble_name (stream, lo);
2101 fprintf (stream, "\n");
2104 /* PRINT_OPERAND. */
2106 void
2107 mmix_print_operand (stream, x, code)
2108 FILE * stream;
2109 rtx x;
2110 int code;
2112 /* When we add support for different codes later, we can, when needed,
2113 drop through to the main handler with a modified operand. */
2114 rtx modified_x = x;
2116 switch (code)
2118 /* Unrelated codes are in alphabetic order. */
2120 case 'B':
2121 if (GET_CODE (x) != CONST_INT)
2122 fatal_insn ("MMIX Internal: Expected a CONST_INT, not this", x);
2123 fprintf (stream, "%d", (int) (INTVAL (x) & 0xff));
2124 return;
2126 case 'H':
2127 /* Highpart. Must be general register, and not the last one, as
2128 that one cannot be part of a consecutive register pair. */
2129 if (REGNO (x) > MMIX_LAST_GENERAL_REGISTER - 1)
2130 internal_error ("MMIX Internal: Bad register: %d", REGNO (x));
2132 /* This is big-endian, so the high-part is the first one. */
2133 fprintf (stream, "%s", reg_names[REGNO (x)]);
2134 return;
2136 case 'L':
2137 /* Lowpart. Must be CONST_INT or general register, and not the last
2138 one, as that one cannot be part of a consecutive register pair. */
2139 if (GET_CODE (x) == CONST_INT)
2141 fprintf (stream, "#%lx",
2142 (unsigned long) (INTVAL (x)
2143 & ((unsigned int) 0x7fffffff * 2 + 1)));
2144 return;
2147 if (GET_CODE (x) == SYMBOL_REF)
2149 output_addr_const (stream, x);
2150 return;
2153 if (REGNO (x) > MMIX_LAST_GENERAL_REGISTER - 1)
2154 internal_error ("MMIX Internal: Bad register: %d", REGNO (x));
2156 /* This is big-endian, so the low-part is + 1. */
2157 fprintf (stream, "%s", reg_names[REGNO (x) + 1]);
2158 return;
2160 /* Can't use 'a' because that's a generic modifier for address
2161 output. */
2162 case 'A':
2163 mmix_output_shiftvalue_op_from_str (stream, "ANDN",
2164 ~(unsigned HOST_WIDEST_INT)
2165 mmix_intval (x));
2166 return;
2168 case 'i':
2169 mmix_output_shiftvalue_op_from_str (stream, "INC",
2170 (unsigned HOST_WIDEST_INT)
2171 mmix_intval (x));
2172 return;
2174 case 'o':
2175 mmix_output_shiftvalue_op_from_str (stream, "OR",
2176 (unsigned HOST_WIDEST_INT)
2177 mmix_intval (x));
2178 return;
2180 case 's':
2181 mmix_output_shiftvalue_op_from_str (stream, "SET",
2182 (unsigned HOST_WIDEST_INT)
2183 mmix_intval (x));
2184 return;
2186 case 'd':
2187 case 'D':
2188 mmix_output_condition (stream, x, (code == 'D'));
2189 return;
2191 case 'e':
2192 /* Output an extra "e" to make fcmpe, fune. */
2193 if (TARGET_FCMP_EPSILON)
2194 fprintf (stream, "e");
2195 return;
2197 case 'm':
2198 /* Output the number minus 1. */
2199 if (GET_CODE (x) != CONST_INT)
2201 fatal_insn ("MMIX Internal: Bad value for 'm', not a CONST_INT",
2204 fprintf (stream, HOST_WIDEST_INT_PRINT_DEC,
2205 (HOST_WIDEST_INT) (mmix_intval (x) - 1));
2206 return;
2208 case 'p':
2209 /* Store the number of registers we want to save. This was setup
2210 by the prologue. The actual operand contains the number of
2211 registers to pass, but we don't use it currently. Anyway, we
2212 need to output the number of saved registers here. */
2213 if (TARGET_ABI_GNU)
2214 fprintf (stream, "%d", mmix_highest_saved_stack_register + 1);
2215 else
2216 /* FIXME: Get the effect of renaming $16, $17.. to the first
2217 unused call-saved reg. */
2218 fprintf (stream, "15");
2219 return;
2221 case 'r':
2222 /* Store the register to output a constant to. */
2223 if (! REG_P (x))
2224 fatal_insn ("MMIX Internal: Expected a register, not this", x);
2225 mmix_output_destination_register = REGNO (x);
2226 return;
2228 case 'I':
2229 /* Output the constant. Note that we use this for floats as well. */
2230 if (GET_CODE (x) != CONST_INT
2231 && (GET_CODE (x) != CONST_DOUBLE
2232 || (GET_MODE (x) != VOIDmode && GET_MODE (x) != DFmode
2233 && GET_MODE (x) != SFmode)))
2234 fatal_insn ("MMIX Internal: Expected a constant, not this", x);
2235 mmix_output_register_setting (stream,
2236 mmix_output_destination_register,
2237 mmix_intval (x), 0);
2238 return;
2240 case 'U':
2241 /* An U for unsigned, if TARGET_ZERO_EXTEND. Ignore the operand. */
2242 if (TARGET_ZERO_EXTEND)
2243 putc ('U', stream);
2244 return;
2246 case 'v':
2247 mmix_output_shifted_value (stream, (HOST_WIDEST_INT) mmix_intval (x));
2248 return;
2250 case 'V':
2251 mmix_output_shifted_value (stream, (HOST_WIDEST_INT) ~mmix_intval (x));
2252 return;
2254 case 'W':
2255 if (GET_CODE (x) != CONST_INT)
2256 fatal_insn ("MMIX Internal: Expected a CONST_INT, not this", x);
2257 fprintf (stream, "#%x", (int) (INTVAL (x) & 0xffff));
2258 return;
2260 case 0:
2261 /* Nothing to do. */
2262 break;
2264 default:
2265 /* Presumably there's a missing case above if we get here. */
2266 internal_error ("MMIX Internal: Missing `%c' case in mmix_print_operand", code);
2269 switch (GET_CODE (modified_x))
2271 case REG:
2272 if (REGNO (modified_x) >= FIRST_PSEUDO_REGISTER)
2273 internal_error ("MMIX Internal: Bad register: %d", REGNO (modified_x));
2274 fprintf (stream, "%s", reg_names[REGNO (modified_x)]);
2275 return;
2277 case MEM:
2278 output_address (XEXP (modified_x, 0));
2279 return;
2281 case CONST_INT:
2282 /* For -2147483648, mmixal complains that the constant does not fit
2283 in 4 bytes, so let's output it as hex. Take care to handle hosts
2284 where HOST_WIDE_INT is longer than an int.
2286 Print small constants +-255 using decimal. */
2288 if (INTVAL (modified_x) > -256 && INTVAL (modified_x) < 256)
2289 fprintf (stream, "%d", (int) (INTVAL (modified_x)));
2290 else
2291 fprintf (stream, "#%x",
2292 (int) (INTVAL (modified_x)) & (unsigned int) ~0);
2293 return;
2295 case CONST_DOUBLE:
2296 /* Do somewhat as CONST_INT. */
2297 mmix_output_octa (stream, mmix_intval (modified_x), 0);
2298 return;
2300 case CONST:
2301 output_addr_const (stream, modified_x);
2302 return;
2304 default:
2305 /* No need to test for all strange things. Let output_addr_const do
2306 it for us. */
2307 if (CONSTANT_P (modified_x)
2308 /* Strangely enough, this is not included in CONSTANT_P.
2309 FIXME: Ask/check about sanity here. */
2310 || GET_CODE (modified_x) == CODE_LABEL)
2312 output_addr_const (stream, modified_x);
2313 return;
2316 /* We need the original here. */
2317 fatal_insn ("MMIX Internal: Cannot decode this operand", x);
2321 /* PRINT_OPERAND_PUNCT_VALID_P. */
2324 mmix_print_operand_punct_valid_p (code)
2325 int code ATTRIBUTE_UNUSED;
2327 /* None at the moment. */
2328 return 0;
2331 /* PRINT_OPERAND_ADDRESS. */
2333 void
2334 mmix_print_operand_address (stream, x)
2335 FILE *stream;
2336 rtx x;
2338 if (REG_P (x))
2340 /* I find the generated assembly code harder to read without
2341 the ",0". */
2342 fprintf (stream, "%s,0",reg_names[REGNO (x)]);
2343 return;
2345 else if (GET_CODE (x) == PLUS)
2347 rtx x1 = XEXP (x, 0);
2348 rtx x2 = XEXP (x, 1);
2350 /* Try swap the order. FIXME: Do we need this? */
2351 if (! REG_P (x1))
2353 rtx tem = x1;
2354 x1 = x2;
2355 x2 = tem;
2358 if (REG_P (x1))
2360 fprintf (stream, "%s,", reg_names[REGNO (x1)]);
2362 if (REG_P (x2))
2364 fprintf (stream, "%s", reg_names[REGNO (x2)]);
2365 return;
2367 else if (GET_CODE (x2) == CONST_INT
2368 && CONST_OK_FOR_LETTER_P (INTVAL (x2), 'I'))
2370 output_addr_const (stream, x2);
2371 return;
2376 fatal_insn ("MMIX Internal: This is not a recognized address", x);
2379 /* ASM_OUTPUT_REG_PUSH. */
2381 void
2382 mmix_asm_output_reg_push (stream, regno)
2383 FILE * stream;
2384 int regno;
2386 fprintf (stream, "\tSUBU %s,%s,8\n\tSTOU %s,%s,0\n",
2387 reg_names[MMIX_STACK_POINTER_REGNUM],
2388 reg_names[MMIX_STACK_POINTER_REGNUM],
2389 reg_names[regno],
2390 reg_names[MMIX_STACK_POINTER_REGNUM]);
2393 /* ASM_OUTPUT_REG_POP. */
2395 void
2396 mmix_asm_output_reg_pop (stream, regno)
2397 FILE * stream;
2398 int regno;
2400 fprintf (stream, "\tLDOU %s,%s,0\n\tINCL %s,8\n",
2401 reg_names[regno],
2402 reg_names[MMIX_STACK_POINTER_REGNUM],
2403 reg_names[MMIX_STACK_POINTER_REGNUM]);
2406 /* ASM_OUTPUT_ADDR_DIFF_ELT. */
2408 void
2409 mmix_asm_output_addr_diff_elt (stream, body, value, rel)
2410 FILE *stream;
2411 rtx body ATTRIBUTE_UNUSED;
2412 int value;
2413 int rel;
2415 fprintf (stream, "\tTETRA L%d-L%d\n", value, rel);
2418 /* ASM_OUTPUT_ADDR_VEC_ELT. */
2420 void
2421 mmix_asm_output_addr_vec_elt (stream, value)
2422 FILE *stream;
2423 int value;
2425 fprintf (stream, "\tOCTA L:%d\n", value);
2428 /* ASM_OUTPUT_SKIP. */
2430 void
2431 mmix_asm_output_skip (stream, nbytes)
2432 FILE *stream;
2433 int nbytes;
2435 fprintf (stream, "\tLOC @+%d\n", nbytes);
2438 /* ASM_OUTPUT_ALIGN. */
2440 void
2441 mmix_asm_output_align (stream, power)
2442 FILE *stream;
2443 int power;
2445 /* We need to record the needed alignment of this section in the object,
2446 so we have to output an alignment directive. Use a .p2align (not
2447 .align) so people will never have to wonder about whether the
2448 argument is in number of bytes or the log2 thereof. We do it in
2449 addition to the LOC directive, so nothing needs tweaking when
2450 copy-pasting assembly into mmixal. */
2451 fprintf (stream, "\t.p2align %d\n", power);
2452 fprintf (stream, "\tLOC @+(%d-@)&%d\n", 1 << power, (1 << power) - 1);
2455 /* DBX_REGISTER_NUMBER. */
2458 mmix_dbx_register_number (regno)
2459 int regno;
2461 /* FIXME: Implement final register renumbering if necessary. (Use
2462 target state in cfun). */
2464 /* We need to renumber registers to get the number of the return address
2465 register in the range 0..255. It is also space-saving if registers
2466 mentioned in the call-frame information (which uses this function by
2467 defaulting DWARF_FRAME_REGNUM to DBX_REGISTER_NUMBER) are numbered
2468 0 .. 63. So map 224 .. 256+15 -> 0 .. 47 and 0 .. 223 -> 48..223+48. */
2469 return regno >= 224 ? (regno - 224) : (regno + 48);
2472 /* End of target macro support functions.
2474 Now MMIX's own functions. First the exported ones. */
2476 /* Output an optimal sequence for setting a register to a specific
2477 constant. Used in an alternative for const_ints in movdi, and when
2478 using large stack-frame offsets.
2480 Use do_begin_end to say if a line-starting TAB and newline before the
2481 first insn and after the last insn is wanted. */
2483 void
2484 mmix_output_register_setting (stream, regno, value, do_begin_end)
2485 FILE *stream;
2486 int regno;
2487 HOST_WIDEST_INT value;
2488 int do_begin_end;
2490 if (do_begin_end)
2491 fprintf (stream, "\t");
2493 if (mmix_shiftable_wyde_value ((unsigned HOST_WIDEST_INT) value))
2495 /* First, the one-insn cases. */
2496 mmix_output_shiftvalue_op_from_str (stream, "SET",
2497 (unsigned HOST_WIDEST_INT)
2498 value);
2499 fprintf (stream, " %s,", reg_names[regno]);
2500 mmix_output_shifted_value (stream, (unsigned HOST_WIDEST_INT) value);
2502 else if (mmix_shiftable_wyde_value (-(unsigned HOST_WIDEST_INT) value))
2504 /* We do this to get a bit more legible assembly code. The next
2505 alternative is mostly redundant with this. */
2507 mmix_output_shiftvalue_op_from_str (stream, "SET",
2508 -(unsigned HOST_WIDEST_INT)
2509 value);
2510 fprintf (stream, " %s,", reg_names[regno]);
2511 mmix_output_shifted_value (stream, -(unsigned HOST_WIDEST_INT) value);
2512 fprintf (stream, "\n\tNEGU %s,0,%s", reg_names[regno],
2513 reg_names[regno]);
2515 else if (mmix_shiftable_wyde_value (~(unsigned HOST_WIDEST_INT) value))
2517 /* Slightly more expensive, the two-insn cases. */
2519 /* FIXME: We could of course also test if 0..255-N or ~(N | 1..255)
2520 is shiftable, or any other one-insn transformation of the value.
2521 FIXME: Check first if the value is "shiftable" by two loading
2522 with two insns, since it makes more readable assembly code (if
2523 anyone else cares). */
2525 mmix_output_shiftvalue_op_from_str (stream, "SET",
2526 ~(unsigned HOST_WIDEST_INT)
2527 value);
2528 fprintf (stream, " %s,", reg_names[regno]);
2529 mmix_output_shifted_value (stream, ~(unsigned HOST_WIDEST_INT) value);
2530 fprintf (stream, "\n\tNOR %s,%s,0", reg_names[regno],
2531 reg_names[regno]);
2533 else
2535 /* The generic case. 2..4 insns. */
2536 static const char *const higher_parts[] = {"L", "ML", "MH", "H"};
2537 const char *op = "SET";
2538 const char *line_begin = "";
2539 int i;
2541 /* Output pertinent parts of the 4-wyde sequence.
2542 Still more to do if we want this to be optimal, but hey...
2543 Note that the zero case has been handled above. */
2544 for (i = 0; i < 4 && value != 0; i++)
2546 if (value & 65535)
2548 fprintf (stream, "%s%s%s %s,#%x", line_begin, op,
2549 higher_parts[i], reg_names[regno],
2550 (int) (value & 65535));
2551 /* The first one sets the rest of the bits to 0, the next
2552 ones add set bits. */
2553 op = "INC";
2554 line_begin = "\n\t";
2557 value >>= 16;
2561 if (do_begin_end)
2562 fprintf (stream, "\n");
2565 /* Return 1 if value is 0..65535*2**(16*N) for N=0..3.
2566 else return 0. */
2569 mmix_shiftable_wyde_value (value)
2570 unsigned HOST_WIDEST_INT value;
2572 /* Shift by 16 bits per group, stop when we've found two groups with
2573 nonzero bits. */
2574 int i;
2575 int has_candidate = 0;
2577 for (i = 0; i < 4; i++)
2579 if (value & 65535)
2581 if (has_candidate)
2582 return 0;
2583 else
2584 has_candidate = 1;
2587 value >>= 16;
2590 return 1;
2593 /* True if this is an address_operand or a symbolic operand. */
2596 mmix_symbolic_or_address_operand (op, mode)
2597 rtx op;
2598 enum machine_mode mode;
2600 switch (GET_CODE (op))
2602 case SYMBOL_REF:
2603 case LABEL_REF:
2604 return 1;
2605 case CONST:
2606 op = XEXP (op, 0);
2607 if ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
2608 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
2609 && (GET_CODE (XEXP (op, 1)) == CONST_INT
2610 || (GET_CODE (XEXP (op, 1)) == CONST_DOUBLE
2611 && GET_MODE (XEXP (op, 1)) == VOIDmode)))
2612 return 1;
2613 /* FALLTHROUGH */
2614 default:
2615 return address_operand (op, mode);
2619 /* True if this is a register or CONST_INT (or CONST_DOUBLE for DImode).
2620 We could narrow the value down with a couple of predicated, but that
2621 doesn't seem to be worth it at the moment. */
2624 mmix_reg_or_constant_operand (op, mode)
2625 rtx op;
2626 enum machine_mode mode;
2628 return register_operand (op, mode)
2629 || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)
2630 || GET_CODE (op) == CONST_INT;
2633 /* True if this is a register with a condition-code mode. */
2636 mmix_reg_cc_operand (op, mode)
2637 rtx op;
2638 enum machine_mode mode;
2640 if (mode == VOIDmode)
2641 mode = GET_MODE (op);
2643 return register_operand (op, mode)
2644 && (mode == CCmode || mode == CC_UNSmode || mode == CC_FPmode
2645 || mode == CC_FPEQmode || mode == CC_FUNmode);
2648 /* True if this is a foldable comparison operator
2649 - one where a the result of (compare:CC (reg) (const_int 0)) can be
2650 replaced by (reg). */
2653 mmix_foldable_comparison_operator (op, mode)
2654 rtx op;
2655 enum machine_mode mode;
2657 RTX_CODE code = GET_CODE (op);
2659 if (mode == VOIDmode)
2660 mode = GET_MODE (op);
2662 if (mode == VOIDmode && GET_RTX_CLASS (GET_CODE (op)) == '<')
2663 mode = GET_MODE (XEXP (op, 0));
2665 return ((mode == CCmode || mode == DImode)
2666 && (code == NE || code == EQ || code == GE || code == GT
2667 || code == LE))
2668 /* FIXME: This may be a stupid trick. What happens when GCC wants to
2669 reverse the condition? Can it do that by itself? Maybe it can
2670 even reverse the condition to fit a foldable one in the first
2671 place? */
2672 || (mode == CC_UNSmode && (code == GTU || code == LEU));
2675 /* Like comparison_operator, but only true if this comparison operator is
2676 applied to a valid mode. Needed to avoid jump.c generating invalid
2677 code with -ffast-math (gcc.dg/20001228-1.c). */
2680 mmix_comparison_operator (op, mode)
2681 rtx op;
2682 enum machine_mode mode;
2684 RTX_CODE code = GET_CODE (op);
2686 /* Comparison operators usually don't have a mode, but let's try and get
2687 one anyway for the day that changes. */
2688 if (mode == VOIDmode)
2689 mode = GET_MODE (op);
2691 /* Get the mode from the first operand if we don't have one. */
2692 if (mode == VOIDmode && GET_RTX_CLASS (GET_CODE (op)) == '<')
2693 mode = GET_MODE (XEXP (op, 0));
2695 /* FIXME: This needs to be kept in sync with the tables in
2696 mmix_output_condition. */
2697 return
2698 (mode == VOIDmode && GET_RTX_CLASS (GET_CODE (op)) == '<')
2699 || (mode == CC_FUNmode
2700 && (code == ORDERED || code == UNORDERED))
2701 || (mode == CC_FPmode
2702 && (code == GT || code == LT))
2703 || (mode == CC_FPEQmode
2704 && (code == NE || code == EQ))
2705 || (mode == CC_UNSmode
2706 && (code == GEU || code == GTU || code == LEU || code == LTU))
2707 || (mode == CCmode
2708 && (code == NE || code == EQ || code == GE || code == GT
2709 || code == LE || code == LT))
2710 || (mode == DImode
2711 && (code == NE || code == EQ || code == GE || code == GT
2712 || code == LE || code == LT || code == LEU || code == GTU));
2715 /* True if this is a register or 0 (int or float). */
2718 mmix_reg_or_0_operand (op, mode)
2719 rtx op;
2720 enum machine_mode mode;
2722 /* FIXME: Is mode calculation necessary and correct? */
2723 return
2724 op == CONST0_RTX (mode == VOIDmode ? GET_MODE (op) : mode)
2725 || register_operand (op, mode);
2728 /* True if this is a register or an int 0..255. */
2731 mmix_reg_or_8bit_operand (op, mode)
2732 rtx op;
2733 enum machine_mode mode;
2735 return register_operand (op, mode)
2736 || (GET_CODE (op) == CONST_INT
2737 && CONST_OK_FOR_LETTER_P (INTVAL (op), 'I'));
2740 /* True if this is a register or an int 0..256. We include 256,
2741 because it can be canonicalized into 255 for comparisons, which is
2742 currently the only use of this predicate.
2743 FIXME: Check that this happens and does TRT. */
2746 mmix_reg_or_8bit_or_256_operand (op, mode)
2747 rtx op;
2748 enum machine_mode mode;
2750 return mmix_reg_or_8bit_operand (op, mode)
2751 || (GET_CODE (op) == CONST_INT && INTVAL (op) == 256);
2754 /* Returns zero if code and mode is not a valid condition from a
2755 compare-type insn. Nonzero if it is. The parameter op, if non-NULL,
2756 is the comparison of mode is CC-somethingmode. */
2759 mmix_valid_comparison (code, mode, op)
2760 RTX_CODE code;
2761 enum machine_mode mode;
2762 rtx op;
2764 if (mode == VOIDmode && op != NULL_RTX)
2765 mode = GET_MODE (op);
2767 /* We don't care to look at these, they should always be valid. */
2768 if (mode == CCmode || mode == CC_UNSmode || mode == DImode)
2769 return 1;
2771 if ((mode == CC_FPmode || mode == DFmode)
2772 && (code == GT || code == LT))
2773 return 1;
2775 if ((mode == CC_FPEQmode || mode == DFmode)
2776 && (code == EQ || code == NE))
2777 return 1;
2779 if ((mode == CC_FUNmode || mode == DFmode)
2780 && (code == ORDERED || code == UNORDERED))
2781 return 1;
2783 return 0;
2786 /* X and Y are two things to compare using CODE. Emit a compare insn if
2787 possible and return the rtx for the cc-reg in the proper mode, or
2788 NULL_RTX if this is not a valid comparison. */
2791 mmix_gen_compare_reg (code, x, y)
2792 RTX_CODE code;
2793 rtx x, y;
2795 enum machine_mode ccmode = SELECT_CC_MODE (code, x, y);
2796 rtx cc_reg;
2798 /* FIXME: Do we get constants here? Of double mode? */
2799 enum machine_mode mode
2800 = GET_MODE (x) == VOIDmode
2801 ? GET_MODE (y)
2802 : GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT ? DFmode : DImode;
2804 if (! mmix_valid_comparison (code, mode, x))
2805 return NULL_RTX;
2807 cc_reg = gen_reg_rtx (ccmode);
2809 /* FIXME: Can we avoid emitting a compare insn here? */
2810 if (! REG_P (x) && ! REG_P (y))
2811 x = force_reg (mode, x);
2813 CANONICALIZE_COMPARISON (code, x, y);
2815 /* If it's not quite right yet, put y in a register. */
2816 if (! REG_P (y)
2817 && (GET_CODE (y) != CONST_INT
2818 || ! CONST_OK_FOR_LETTER_P (INTVAL (y), 'I')))
2819 y = force_reg (mode, y);
2821 emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
2822 gen_rtx_COMPARE (ccmode, x, y)));
2824 return cc_reg;
2827 /* Local (static) helper functions. */
2829 /* Print operator suitable for doing something with a shiftable
2830 wyde. The type of operator is passed as a asm output modifier. */
2832 static void
2833 mmix_output_shiftvalue_op_from_str (stream, mainop, value)
2834 FILE *stream;
2835 const char *mainop;
2836 HOST_WIDEST_INT value;
2838 static const char *const op_part[] = {"L", "ML", "MH", "H"};
2839 int i;
2841 if (! mmix_shiftable_wyde_value (value))
2843 char s[sizeof ("0xffffffffffffffff")];
2844 sprintf (s, HOST_WIDEST_INT_PRINT_HEX, value);
2845 internal_error ("MMIX Internal: %s is not a shiftable int", s);
2848 for (i = 0; i < 4; i++)
2850 /* We know we're through when we find one-bits in the low
2851 16 bits. */
2852 if (value & 0xffff)
2854 fprintf (stream, "%s%s", mainop, op_part[i]);
2855 return;
2857 value >>= 16;
2860 /* No bits set? Then it must have been zero. */
2861 fprintf (stream, "%sL", mainop);
2864 /* Print a 64-bit value, optionally prefixed by assembly pseudo. */
2866 static void
2867 mmix_output_octa (stream, value, do_begin_end)
2868 FILE *stream;
2869 HOST_WIDEST_INT value;
2870 int do_begin_end;
2872 /* Snipped from final.c:output_addr_const. We need to avoid the
2873 presumed universal "0x" prefix. We can do it by replacing "0x" with
2874 "#0" here; we must avoid a space in the operands and no, the zero
2875 won't cause the number to be assumed in octal format. */
2876 char hex_format[sizeof (HOST_WIDEST_INT_PRINT_HEX)];
2878 if (do_begin_end)
2879 fprintf (stream, "\tOCTA ");
2881 strcpy (hex_format, HOST_WIDEST_INT_PRINT_HEX);
2882 hex_format[0] = '#';
2883 hex_format[1] = '0';
2885 /* Provide a few alternative output formats depending on the number, to
2886 improve legibility of assembler output. */
2887 if ((value < (HOST_WIDEST_INT) 0 && value > (HOST_WIDEST_INT) -10000)
2888 || (value >= (HOST_WIDEST_INT) 0 && value <= (HOST_WIDEST_INT) 16384))
2889 fprintf (stream, "%d", (int) value);
2890 else if (value > (HOST_WIDEST_INT) 0
2891 && value < ((HOST_WIDEST_INT) 1 << 31) * 2)
2892 fprintf (stream, "#%x", (unsigned int) value);
2893 else
2894 fprintf (stream, hex_format, value);
2896 if (do_begin_end)
2897 fprintf (stream, "\n");
2900 /* Print the presumed shiftable wyde argument shifted into place (to
2901 be output with an operand). */
2903 static void
2904 mmix_output_shifted_value (stream, value)
2905 FILE * stream;
2906 HOST_WIDEST_INT value;
2908 int i;
2910 if (! mmix_shiftable_wyde_value (value))
2912 char s[16+2+1];
2913 sprintf (s, HOST_WIDEST_INT_PRINT_HEX, value);
2914 internal_error ("MMIX Internal: %s is not a shiftable int", s);
2917 for (i = 0; i < 4; i++)
2919 /* We know we're through when we find one-bits in the low 16 bits. */
2920 if (value & 0xffff)
2922 fprintf (stream, "#%x", (int) (value & 0xffff));
2923 return;
2926 value >>= 16;
2929 /* No bits set? Then it must have been zero. */
2930 fprintf (stream, "0");
2933 /* Output an MMIX condition name corresponding to an operator
2934 and operands:
2935 (comparison_operator [(comparison_operator ...) (const_int 0)])
2936 which means we have to look at *two* operators.
2938 The argument "reversed" refers to reversal of the condition (not the
2939 same as swapping the arguments). */
2941 static void
2942 mmix_output_condition (stream, x, reversed)
2943 FILE *stream;
2944 rtx x;
2945 int reversed;
2947 struct cc_conv
2949 RTX_CODE cc;
2951 /* The normal output cc-code. */
2952 const char *const normal;
2954 /* The reversed cc-code, or NULL if invalid. */
2955 const char *const reversed;
2958 struct cc_type_conv
2960 enum machine_mode cc_mode;
2962 /* Terminated with {NIL, NULL, NULL} */
2963 const struct cc_conv *const convs;
2966 #undef CCEND
2967 #define CCEND {NIL, NULL, NULL}
2969 static const struct cc_conv cc_fun_convs[]
2970 = {{ORDERED, "Z", "P"},
2971 {UNORDERED, "P", "Z"},
2972 CCEND};
2973 static const struct cc_conv cc_fp_convs[]
2974 = {{GT, "P", NULL},
2975 {LT, "N", NULL},
2976 CCEND};
2977 static const struct cc_conv cc_fpeq_convs[]
2978 = {{NE, "Z", "P"},
2979 {EQ, "P", "Z"},
2980 CCEND};
2981 static const struct cc_conv cc_uns_convs[]
2982 = {{GEU, "NN", "N"},
2983 {GTU, "P", "NP"},
2984 {LEU, "NP", "P"},
2985 {LTU, "N", "NN"},
2986 CCEND};
2987 static const struct cc_conv cc_signed_convs[]
2988 = {{NE, "NZ", "Z"},
2989 {EQ, "Z", "NZ"},
2990 {GE, "NN", "N"},
2991 {GT, "P", "NP"},
2992 {LE, "NP", "P"},
2993 {LT, "N", "NN"},
2994 CCEND};
2995 static const struct cc_conv cc_di_convs[]
2996 = {{NE, "NZ", "Z"},
2997 {EQ, "Z", "NZ"},
2998 {GE, "NN", "N"},
2999 {GT, "P", "NP"},
3000 {LE, "NP", "P"},
3001 {LT, "N", "NN"},
3002 {GTU, "NZ", "Z"},
3003 {LEU, "Z", "NZ"},
3004 CCEND};
3005 #undef CCEND
3007 static const struct cc_type_conv cc_convs[]
3008 = {{CC_FUNmode, cc_fun_convs},
3009 {CC_FPmode, cc_fp_convs},
3010 {CC_FPEQmode, cc_fpeq_convs},
3011 {CC_UNSmode, cc_uns_convs},
3012 {CCmode, cc_signed_convs},
3013 {DImode, cc_di_convs}};
3015 unsigned int i;
3016 int j;
3018 enum machine_mode mode = GET_MODE (XEXP (x, 0));
3019 RTX_CODE cc = GET_CODE (x);
3021 for (i = 0; i < sizeof (cc_convs)/sizeof(*cc_convs); i++)
3023 if (mode == cc_convs[i].cc_mode)
3025 for (j = 0; cc_convs[i].convs[j].cc != NIL; j++)
3026 if (cc == cc_convs[i].convs[j].cc)
3028 const char *mmix_cc
3029 = (reversed ? cc_convs[i].convs[j].reversed
3030 : cc_convs[i].convs[j].normal);
3032 if (mmix_cc == NULL)
3033 fatal_insn ("MMIX Internal: Trying to output invalidly\
3034 reversed condition:", x);
3036 fprintf (stream, "%s", mmix_cc);
3037 return;
3040 fatal_insn ("MMIX Internal: What's the CC of this?", x);
3044 fatal_insn ("MMIX Internal: What is the CC of this?", x);
3047 /* Return the bit-value for a const_int or const_double. */
3049 static HOST_WIDEST_INT
3050 mmix_intval (x)
3051 rtx x;
3053 unsigned HOST_WIDEST_INT retval;
3055 if (GET_CODE (x) == CONST_INT)
3056 return INTVAL (x);
3058 /* We make a little song and dance because converting to long long in
3059 gcc-2.7.2 is broken. I still want people to be able to use it for
3060 cross-compilation to MMIX. */
3061 if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == VOIDmode)
3063 if (sizeof (HOST_WIDE_INT) < sizeof (HOST_WIDEST_INT))
3065 retval = (unsigned) CONST_DOUBLE_LOW (x) / 2;
3066 retval *= 2;
3067 retval |= CONST_DOUBLE_LOW (x) & 1;
3069 retval |=
3070 (unsigned HOST_WIDEST_INT) CONST_DOUBLE_HIGH (x)
3071 << (HOST_BITS_PER_LONG);
3073 else
3074 retval = CONST_DOUBLE_HIGH (x);
3076 return retval;
3079 if (GET_CODE (x) == CONST_DOUBLE)
3081 REAL_VALUE_TYPE value;
3083 /* FIXME: This macro is not in the manual but should be. */
3084 REAL_VALUE_FROM_CONST_DOUBLE (value, x);
3086 if (GET_MODE (x) == DFmode)
3088 long bits[2];
3090 REAL_VALUE_TO_TARGET_DOUBLE (value, bits);
3092 if (sizeof (long) < sizeof (HOST_WIDEST_INT))
3094 retval = (unsigned long) bits[1] / 2;
3095 retval *= 2;
3096 retval |= (unsigned long) bits[1] & 1;
3097 retval
3098 |= (unsigned HOST_WIDEST_INT) bits[0]
3099 << (sizeof (bits[0]) * 8);
3101 else
3102 retval = (unsigned long) bits[1];
3104 return retval;
3106 else if (GET_MODE (x) == SFmode)
3108 long bits;
3109 REAL_VALUE_TO_TARGET_SINGLE (value, bits);
3111 return (unsigned long) bits;
3115 fatal_insn ("MMIX Internal: This is not a constant:", x);
3119 * Local variables:
3120 * eval: (c-set-style "gnu")
3121 * indent-tabs-mode: t
3122 * End: