]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/mmix/mmix.c
* exception.cc (std::abort): Mark as noreturn.
[thirdparty/gcc.git] / gcc / config / mmix / mmix.c
CommitLineData
68cbb7e3 1/* Definitions of target machine for GNU compiler, for MMIX.
f38f90bf 2 Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
68cbb7e3 3 Contributed by Hans-Peter Nilsson (hp@bitrange.com)
4
5This file is part of GNU CC.
6
7GNU CC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU CC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU CC; see the file COPYING. If not, write to
19the Free Software Foundation, 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
21
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"
43
44/* First some local helper definitions. */
45#define MMIX_FIRST_GLOBAL_REGNUM 32
46
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)
51
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 ())
57
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))
64
65/* The canonical saved comparison operands for non-cc0 machines, set in
66 the compare expander. */
67rtx mmix_compare_op0;
68rtx mmix_compare_op1;
69
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. */
25037517 73const char *mmix_cc1_ignored_option;
68cbb7e3 74
75/* Declarations of locals. */
76
77/* This is used in the prologue for what number to pass in a PUSHJ or
78 PUSHGO insn. */
79static int mmix_highest_saved_stack_register;
80
81/* Intermediate for insn output. */
82static int mmix_output_destination_register;
83
84static void mmix_output_shiftvalue_op_from_str
85 PARAMS ((FILE *, const char *, HOST_WIDEST_INT));
86static void mmix_output_shifted_value PARAMS ((FILE *, HOST_WIDEST_INT));
87static void mmix_output_condition PARAMS ((FILE *, rtx, int));
88static HOST_WIDEST_INT mmix_intval PARAMS ((rtx));
89static void mmix_output_octa PARAMS ((FILE *, HOST_WIDEST_INT, int));
58356836 90static bool mmix_assemble_integer PARAMS ((rtx, unsigned int, int));
68cbb7e3 91static void mmix_init_machine_status PARAMS ((struct function *));
92
93extern void mmix_target_asm_function_prologue
94 PARAMS ((FILE *, HOST_WIDE_INT));
95extern void mmix_target_asm_function_epilogue
96 PARAMS ((FILE *, HOST_WIDE_INT));
97
98
99/* Target structure macros. Listed by node. See `Using and Porting GCC'
100 for a general description. */
101
102/* Node: Function Entry */
103
58356836 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
114
68cbb7e3 115#undef TARGET_ASM_FUNCTION_PROLOGUE
116#define TARGET_ASM_FUNCTION_PROLOGUE mmix_target_asm_function_prologue
117
118#undef TARGET_ASM_FUNCTION_EPILOGUE
119#define TARGET_ASM_FUNCTION_EPILOGUE mmix_target_asm_function_epilogue
120
121struct gcc_target targetm = TARGET_INITIALIZER;
122
123/* Functions that are expansions for target macros.
124 See Target Macros in `Using and Porting GCC'. */
125
126/* OVERRIDE_OPTIONS. */
127
128void
129mmix_override_options ()
130{
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)
137 {
138 warning ("-f%s not supported: ignored", (flag_pic > 1) ? "PIC" : "pic");
139 flag_pic = 0;
140 }
141
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);
146}
147
148/* INIT_EXPANDERS. */
149
150void
151mmix_init_expanders ()
152{
153 init_machine_status = mmix_init_machine_status;
154}
155
156/* Set the per-function data. */
157
25037517 158static void
68cbb7e3 159mmix_init_machine_status (f)
160 struct function *f;
161{
162 f->machine = xcalloc (1, sizeof (struct machine_function));
163}
164
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. */
169
170int
171mmix_data_alignment (type, basic_align)
172 tree type ATTRIBUTE_UNUSED;
173 int basic_align;
174{
175 if (basic_align < 32)
176 return 32;
177
178 return basic_align;
179}
180
181/* CONSTANT_ALIGNMENT. */
182
183int
184mmix_constant_alignment (constant, basic_align)
185 tree constant ATTRIBUTE_UNUSED;
186 int basic_align;
187{
188 if (basic_align < 32)
189 return 32;
190
191 return basic_align;
192}
193
194/* LOCAL_ALIGNMENT. */
195
196int
197mmix_local_alignment (type, basic_align)
198 tree type ATTRIBUTE_UNUSED;
199 int basic_align;
200{
201 if (basic_align < 32)
202 return 32;
203
204 return basic_align;
205}
206
207/* CONDITIONAL_REGISTER_USAGE. */
208
209void
210mmix_conditional_register_usage ()
211{
212 int i;
213
214 if (TARGET_ABI_GNU)
215 {
216 static const int gnu_abi_reg_alloc_order[]
217 = MMIX_GNU_ABI_REG_ALLOC_ORDER;
218
219 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
220 reg_alloc_order[i] = gnu_abi_reg_alloc_order[i];
221
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;
f0b228a5 231
232 /* "Unfix" the parameter registers. */
233 for (i = MMIX_RESERVED_GNU_ARG_0_REGNUM;
234 i < MMIX_RESERVED_GNU_ARG_0_REGNUM + MMIX_MAX_ARGS_IN_REGS;
235 i++)
236 fixed_regs[i] = 0;
68cbb7e3 237 }
238
239 /* Step over the ":" in special register names. */
240 if (! TARGET_TOPLEVEL_SYMBOLS)
241 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
242 if (reg_names[i][0] == ':')
243 reg_names[i]++;
244}
245
246/* PREFERRED_RELOAD_CLASS.
247 We need to extend the reload class of REMAINDER_REG and HIMULT_REG. */
248
249enum reg_class
250mmix_preferred_reload_class (x, class)
251 rtx x ATTRIBUTE_UNUSED;
252 enum reg_class class;
253{
254 /* FIXME: Revisit. */
255 return GET_CODE (x) == MOD && GET_MODE (x) == DImode
256 ? REMAINDER_REG : class;
257}
258
259/* PREFERRED_OUTPUT_RELOAD_CLASS.
260 We need to extend the reload class of REMAINDER_REG and HIMULT_REG. */
261
262enum reg_class
263mmix_preferred_output_reload_class (x, class)
264 rtx x ATTRIBUTE_UNUSED;
265 enum reg_class class;
266{
267 /* FIXME: Revisit. */
268 return GET_CODE (x) == MOD && GET_MODE (x) == DImode
269 ? REMAINDER_REG : class;
270}
271
272/* SECONDARY_RELOAD_CLASS.
273 We need to reload regs of REMAINDER_REG and HIMULT_REG elsewhere. */
274
275enum reg_class
276mmix_secondary_reload_class (class, mode, x, in_p)
277 enum reg_class class;
0103ffd2 278 enum machine_mode mode ATTRIBUTE_UNUSED;
279 rtx x ATTRIBUTE_UNUSED;
280 int in_p ATTRIBUTE_UNUSED;
68cbb7e3 281{
282 if (class == REMAINDER_REG
283 || class == HIMULT_REG
284 || class == SYSTEM_REGS)
285 return GENERAL_REGS;
286
68cbb7e3 287 return NO_REGS;
288}
289
290/* CONST_OK_FOR_LETTER_P. */
291
292int
293mmix_const_ok_for_letter_p (value, c)
294 HOST_WIDE_INT value;
295 int c;
296{
297 return
298 (c == 'I' ? value >= 0 && value <= 255
299 : c == 'J' ? value >= 0 && value <= 65535
300 : c == 'K' ? value <= 0 && value >= -255
301 : c == 'L' ? mmix_shiftable_wyde_value (value)
302 : c == 'M' ? value == 0
303 : c == 'N' ? mmix_shiftable_wyde_value (~value)
304 : c == 'O' ? (value == 3 || value == 5 || value == 9
305 || value == 17)
306 : 0);
307}
308
309/* CONST_DOUBLE_OK_FOR_LETTER_P. */
310
311int
312mmix_const_double_ok_for_letter_p (value, c)
313 rtx value;
314 int c;
315{
316 return
317 (c == 'G' ? value == CONST0_RTX (GET_MODE (value))
318 : 0);
319}
320
321/* EXTRA_CONSTRAINT.
322 We need this since our constants are not always expressible as
323 CONST_INT:s, but rather often as CONST_DOUBLE:s. */
324
325int
0103ffd2 326mmix_extra_constraint (x, c, strict)
68cbb7e3 327 rtx x;
328 int c;
0103ffd2 329 int strict;
68cbb7e3 330{
331 HOST_WIDEST_INT value;
332
0103ffd2 333 /* When checking for an address, we need to handle strict vs. non-strict
334 register checks. Don't use address_operand, but instead its
335 equivalent (its callee, which it is just a wrapper for),
336 memory_operand_p and the strict-equivalent strict_memory_address_p. */
68cbb7e3 337 if (c == 'U')
0103ffd2 338 return
339 strict
340 ? strict_memory_address_p (Pmode, x)
341 : memory_address_p (Pmode, x);
68cbb7e3 342
f0b228a5 343 /* R asks whether x is to be loaded with GETA or something else. Right
344 now, only a SYMBOL_REF and LABEL_REF can fit for
345 TARGET_BASE_ADDRESSES.
346
347 Only constant symbolic addresses apply. With TARGET_BASE_ADDRESSES,
348 we just allow straight LABEL_REF or SYMBOL_REFs with SYMBOL_REF_FLAG
349 set right now; only function addresses and code labels. If we change
350 to let SYMBOL_REF_FLAG be set on other symbols, we have to check
351 inside CONST expressions. When TARGET_BASE_ADDRESSES is not in
352 effect, a "raw" constant check together with mmix_constant_address_p
353 is all that's needed; we want all constant addresses to be loaded
354 with GETA then. */
355 if (c == 'R')
356 return
357 GET_CODE (x) != CONST_INT && GET_CODE (x) != CONST_DOUBLE
358 && mmix_constant_address_p (x)
359 && (! TARGET_BASE_ADDRESSES
360 || (GET_CODE (x) == LABEL_REF
361 || (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FLAG (x))));
362
68cbb7e3 363 if (GET_CODE (x) != CONST_DOUBLE || GET_MODE (x) != VOIDmode)
364 return 0;
365
366 value = mmix_intval (x);
367
368 /* We used to map Q->J, R->K, S->L, T->N, U->O, but we don't have to any
f0b228a5 369 more ('U' taken for address_operand, 'R' similarly). Some letters map
370 outside of CONST_INT, though; we still use 'S' and 'T'. */
68cbb7e3 371 if (c == 'S')
372 return mmix_shiftable_wyde_value (value);
373 else if (c == 'T')
374 return mmix_shiftable_wyde_value (~value);
375 return 0;
376}
377
378/* DYNAMIC_CHAIN_ADDRESS. */
379
380rtx
381mmix_dynamic_chain_address (frame)
382 rtx frame;
383{
384 /* FIXME: the frame-pointer is stored at offset -8 from the current
385 frame-pointer. Unfortunately, the caller assumes that a
386 frame-pointer is present for *all* previous frames. There should be
387 a way to say that that cannot be done, like for RETURN_ADDR_RTX. */
388 return plus_constant (frame, -8);
389}
390
391/* STARTING_FRAME_OFFSET. */
392
393int
394mmix_starting_frame_offset ()
395{
396 /* The old frame pointer is in the slot below the new one, so
397 FIRST_PARM_OFFSET does not need to depend on whether the
398 frame-pointer is needed or not. We have to adjust for the register
399 stack pointer being located below the saved frame pointer.
400 Similarly, we store the return address on the stack too, for
401 exception handling, and always if we save the register stack pointer. */
402 return
403 (-8
404 + (MMIX_CFUN_HAS_LANDING_PAD
405 ? -16 : (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS ? -8 : 0)));
406}
407
408/* RETURN_ADDR_RTX. */
409
410rtx
411mmix_return_addr_rtx (count, frame)
412 int count;
413 rtx frame ATTRIBUTE_UNUSED;
414{
415 return count == 0
416 ? (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS
417 /* FIXME: Set frame_alias_set on the following. */
418 ? validize_mem (gen_rtx_MEM (Pmode, plus_constant (frame_pointer_rtx, -16)))
419 : get_hard_reg_initial_val (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM))
420 : NULL_RTX;
421}
422
423/* SETUP_FRAME_ADDRESSES. */
424
425void
426mmix_setup_frame_addresses ()
427{
428 /* Nothing needed at the moment. */
429}
430
431/* The difference between the (imaginary) frame pointer and the stack
432 pointer. Used to eliminate the frame pointer. */
433
434int
435mmix_initial_elimination_offset (fromreg, toreg)
436 int fromreg;
437 int toreg;
438{
439 int regno;
440 int fp_sp_offset
441 = (get_frame_size () + current_function_outgoing_args_size + 7) & ~7;
442
443 /* There is no actual difference between these two. */
444 if (fromreg == MMIX_ARG_POINTER_REGNUM
445 && toreg == MMIX_FRAME_POINTER_REGNUM)
446 return 0;
447
448 /* The difference is the size of local variables plus the size of
449 outgoing function arguments that would normally be passed as
450 registers but must be passed on stack because we're out of
451 function-argument registers. Only global saved registers are
452 counted; the others go on the register stack.
453
454 The frame-pointer is counted too if it is what is eliminated, as we
455 need to balance the offset for it from STARTING_FRAME_OFFSET.
456
457 Also add in the slot for the register stack pointer we save if we
458 have a landing pad.
459
460 Unfortunately, we can't access $0..$14, from unwinder code easily, so
461 store the return address in a frame slot too. FIXME: Only for
462 non-leaf functions. FIXME: Always with a landing pad, because it's
463 hard to know whether we need the other at the time we know we need
464 the offset for one (and have to state it). It's a kludge until we
465 can express the register stack in the EH frame info.
466
467 We have to do alignment here; get_frame_size will not return a
468 multiple of STACK_BOUNDARY. FIXME: Add note in manual. */
469
470 for (regno = MMIX_FIRST_GLOBAL_REGNUM;
471 regno <= 255;
472 regno++)
473 if ((regs_ever_live[regno] && ! call_used_regs[regno])
474 || IS_MMIX_EH_RETURN_DATA_REG (regno))
475 fp_sp_offset += 8;
476
477 return fp_sp_offset
478 + (MMIX_CFUN_HAS_LANDING_PAD
479 ? 16 : (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS ? 8 : 0))
480 + (fromreg == MMIX_ARG_POINTER_REGNUM ? 0 : 8);
481}
482
483/* Return an rtx for a function argument to go in a register, and 0 for
484 one that must go on stack. */
485
486rtx
487mmix_function_arg (argsp, mode, type, named, incoming)
488 const CUMULATIVE_ARGS * argsp;
489 enum machine_mode mode;
490 tree type;
491 int named ATTRIBUTE_UNUSED;
492 int incoming;
493{
494 /* Handling of the positional dummy parameter for varargs gets nasty.
495 Check execute/991216-3 and function.c:assign_params. We have to say
496 that the dummy parameter goes on stack in order to get the correct
497 offset when va_start and va_arg is applied. FIXME: Should do TRT by
498 itself in the gcc core. */
499 if ((! named && incoming && current_function_varargs) || argsp->now_varargs)
500 return NULL_RTX;
501
502 /* Last-argument marker. */
503 if (type == void_type_node)
504 return (argsp->regs < MMIX_MAX_ARGS_IN_REGS)
505 ? gen_rtx_REG (mode,
506 (incoming
507 ? MMIX_FIRST_INCOMING_ARG_REGNUM
508 : MMIX_FIRST_ARG_REGNUM) + argsp->regs)
509 : NULL_RTX;
510
511 return (argsp->regs < MMIX_MAX_ARGS_IN_REGS
512 && !MUST_PASS_IN_STACK (mode, type)
513 && (GET_MODE_BITSIZE (mode) <= 64
514 || argsp->lib
515 || TARGET_LIBFUNC))
516 ? gen_rtx_REG (mode,
517 (incoming
518 ? MMIX_FIRST_INCOMING_ARG_REGNUM
519 : MMIX_FIRST_ARG_REGNUM)
520 + argsp->regs)
521 : NULL_RTX;
522}
523
524/* Returns nonzero for everything that goes by reference, 0 for
525 everything that goes by value. */
526
527int
528mmix_function_arg_pass_by_reference (argsp, mode, type, named)
529 const CUMULATIVE_ARGS * argsp;
530 enum machine_mode mode;
531 tree type;
532 int named ATTRIBUTE_UNUSED;
533{
534 /* FIXME: Check: I'm not sure the MUST_PASS_IN_STACK check is
535 necessary. */
536 return
537 MUST_PASS_IN_STACK (mode, type)
538 || (MMIX_FUNCTION_ARG_SIZE (mode, type) > 8
539 && !TARGET_LIBFUNC
540 && !argsp->lib);
541}
542
543/* Return nonzero if regno is a register number where a parameter is
544 passed, and 0 otherwise. */
545
546int
547mmix_function_arg_regno_p (regno, incoming)
548 int regno;
549 int incoming;
550{
551 int first_arg_regnum
552 = incoming ? MMIX_FIRST_INCOMING_ARG_REGNUM : MMIX_FIRST_ARG_REGNUM;
553
554 return regno >= first_arg_regnum
555 && regno < first_arg_regnum + MMIX_MAX_ARGS_IN_REGS;
556}
557
558/* FUNCTION_OUTGOING_VALUE. */
559
560rtx
561mmix_function_outgoing_value (valtype, func)
562 tree valtype;
563 tree func ATTRIBUTE_UNUSED;
564{
565 enum machine_mode mode = TYPE_MODE (valtype);
68cbb7e3 566 enum machine_mode cmode;
567 int first_val_regnum = MMIX_OUTGOING_RETURN_VALUE_REGNUM;
568 rtx vec[MMIX_MAX_REGS_FOR_VALUE];
569 int i;
570 int nregs;
571
572 /* Return values that fit in a register need no special handling.
573 There's no register hole when parameters are passed in global
574 registers. */
575 if (TARGET_ABI_GNU
576 || GET_MODE_BITSIZE (mode) <= BITS_PER_WORD)
577 return
578 gen_rtx_REG (mode, MMIX_OUTGOING_RETURN_VALUE_REGNUM);
579
580 /* A complex type, made up of components. */
581 cmode = TYPE_MODE (TREE_TYPE (valtype));
582 nregs = ((GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD);
583
584 /* We need to take care of the effect of the register hole on return
585 values of large sizes; the last register will appear as the first
586 register, with the rest shifted. (For complex modes, this is just
587 swapped registers.) */
588
589 if (nregs > MMIX_MAX_REGS_FOR_VALUE)
68435912 590 internal_error ("too large function value type, needs %d registers,\
68cbb7e3 591 have only %d registers for this", nregs, MMIX_MAX_REGS_FOR_VALUE);
592
593 /* FIXME: Maybe we should handle structure values like this too
594 (adjusted for BLKmode), perhaps for both ABI:s. */
595 for (i = 0; i < nregs - 1; i++)
596 vec[i]
597 = gen_rtx_EXPR_LIST (VOIDmode,
598 gen_rtx_REG (cmode, first_val_regnum + i),
599 GEN_INT ((i + 1) * BITS_PER_UNIT));
600
601 vec[nregs - 1]
602 = gen_rtx_EXPR_LIST (VOIDmode,
603 gen_rtx_REG (cmode, first_val_regnum + nregs - 1),
604 GEN_INT (0));
605
606 return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nregs, vec));
607}
608
609/* EH_RETURN_DATA_REGNO. */
610
611int
612mmix_eh_return_data_regno (n)
613 int n ATTRIBUTE_UNUSED;
614{
615 if (n >= 0 && n < 4)
616 return MMIX_EH_RETURN_DATA_REGNO_START + n;
617
618 return INVALID_REGNUM;
619}
620
621/* EH_RETURN_STACKADJ_RTX. */
622
623rtx
624mmix_eh_return_stackadj_rtx ()
625{
626 return gen_rtx_REG (Pmode, MMIX_EH_RETURN_STACKADJ_REGNUM);
627}
628
629/* EH_RETURN_HANDLER_RTX. */
630
631rtx
632mmix_eh_return_handler_rtx ()
633{
634 return
635 gen_rtx_REG (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
636}
637
638/* ASM_PREFERRED_EH_DATA_FORMAT. */
639
640int
641mmix_asm_preferred_eh_data_format (code, global)
642 int code ATTRIBUTE_UNUSED;
643 int global ATTRIBUTE_UNUSED;
644{
645 /* This is the default (was at 2001-07-20). Revisit when needed. */
646 return DW_EH_PE_absptr;
647}
648
649/* Emit the function prologue. For simplicity while the port is still
650 in a flux, we do it as text rather than the now preferred RTL way,
651 as (define_insn "function_prologue").
652
653 FIXME: Translate to RTL and/or optimize some of the DWARF 2 stuff. */
654
655void
656mmix_target_asm_function_prologue (stream, locals_size)
657 FILE *stream;
658 HOST_WIDE_INT locals_size;
659{
660 int regno;
661 int stack_space_to_allocate
662 = (current_function_outgoing_args_size
663 + current_function_pretend_args_size
664 + (int) locals_size + 8 + 7) & ~7;
665 int offset = -8;
666 int empty_stack_frame
667 = (current_function_outgoing_args_size == 0
668 && locals_size == 0
669 && current_function_pretend_args_size == 0
670 && current_function_varargs == 0
671 && current_function_stdarg == 0);
672 int doing_dwarf = dwarf2out_do_frame ();
673 long cfa_offset = 0;
674
675 /* Guard our assumptions. Very low priority FIXME. */
676 if (locals_size != (int) locals_size)
677 error ("stack frame too big");
678
679 /* Add room needed to save global non-register-stack registers. */
680 for (regno = 255;
681 regno >= MMIX_FIRST_GLOBAL_REGNUM;
682 regno--)
683 /* Note that we assume that the frame-pointer-register is one of these
684 registers, in which case we don't count it here. */
685 if ((((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
686 && regs_ever_live[regno] && !call_used_regs[regno]))
687 || IS_MMIX_EH_RETURN_DATA_REG (regno))
688 stack_space_to_allocate += 8;
689
690 /* If we do have a frame-pointer, add room for it. */
691 if (frame_pointer_needed)
692 stack_space_to_allocate += 8;
693
694 /* If we have a non-local label, we need to be able to unwind to it, so
695 store the current register stack pointer. Also store the return
696 address if we do that. */
697 if (MMIX_CFUN_HAS_LANDING_PAD)
698 stack_space_to_allocate += 16;
699 else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
700 /* If we do have a saved return-address slot, add room for it. */
701 stack_space_to_allocate += 8;
702
703 /* Make sure we don't get an unaligned stack. */
704 if ((stack_space_to_allocate % 8) != 0)
68435912 705 internal_error ("stack frame not a multiple of 8 bytes: %d",
68cbb7e3 706 stack_space_to_allocate);
707
708 if (current_function_pretend_args_size)
709 {
710 int mmix_first_vararg_reg
711 = (MMIX_FIRST_INCOMING_ARG_REGNUM
712 + (MMIX_MAX_ARGS_IN_REGS
713 - current_function_pretend_args_size / 8));
714
715 for (regno
716 = MMIX_FIRST_INCOMING_ARG_REGNUM + MMIX_MAX_ARGS_IN_REGS - 1;
717 regno >= mmix_first_vararg_reg;
718 regno--)
719 {
720 if (offset < 0)
721 {
722 int stack_chunk
723 = stack_space_to_allocate > (256 - 8)
724 ? (256 - 8) : stack_space_to_allocate;
725
726 fprintf (stream, "\tSUBU %s,%s,%d\n",
727 reg_names[MMIX_STACK_POINTER_REGNUM],
728 reg_names[MMIX_STACK_POINTER_REGNUM],
729 stack_chunk);
730
731 if (doing_dwarf)
732 {
733 /* Each call to dwarf2out_def_cfa overrides the previous
734 setting; they don't accumulate. We must keep track
735 of the offset ourselves. */
736 cfa_offset += stack_chunk;
737 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
738 cfa_offset);
739 }
740 offset += stack_chunk;
741 stack_space_to_allocate -= stack_chunk;
742 }
743
744 fprintf (stream, "\tSTOU %s,%s,%d\n", reg_names[regno],
745 reg_names[MMIX_STACK_POINTER_REGNUM],
746 offset);
747
748 /* These registers aren't actually saved (as in "will be
749 restored"), so don't tell DWARF2 they're saved. */
750
751 offset -= 8;
752 }
753 }
754
755 /* In any case, skip over the return-address slot. FIXME: Not needed
756 now. */
757 offset -= 8;
758
759 /* Store the frame-pointer. */
760
761 if (frame_pointer_needed)
762 {
763 empty_stack_frame = 0;
764
765 if (offset < 0)
766 {
767 /* Get 8 less than otherwise, since we need to reach offset + 8. */
768 int stack_chunk
769 = stack_space_to_allocate > (256 - 8 - 8)
770 ? (256 - 8 - 8) : stack_space_to_allocate;
771
772 fprintf (stream, "\tSUBU %s,%s,%d\n",
773 reg_names[MMIX_STACK_POINTER_REGNUM],
774 reg_names[MMIX_STACK_POINTER_REGNUM],
775 stack_chunk);
776 if (doing_dwarf)
777 {
778 cfa_offset += stack_chunk;
779 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
780 cfa_offset);
781 }
782 offset += stack_chunk;
783 stack_space_to_allocate -= stack_chunk;
784 }
785
786 fprintf (stream, "\tSTOU %s,%s,%d\n\tADDU %s,%s,%d\n",
787 reg_names[MMIX_FRAME_POINTER_REGNUM],
788 reg_names[MMIX_STACK_POINTER_REGNUM],
789 offset,
790 reg_names[MMIX_FRAME_POINTER_REGNUM],
791 reg_names[MMIX_STACK_POINTER_REGNUM],
792 offset + 8);
793 if (doing_dwarf)
794 dwarf2out_reg_save ("", MMIX_FRAME_POINTER_REGNUM,
795 -cfa_offset + offset);
796
797 offset -= 8;
798 }
799
800 if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
801 {
802 /* Store the return-address, if one is needed on the stack. */
803 empty_stack_frame = 0;
804
805 if (offset < 0)
806 {
807 /* Get 8 less than otherwise, since we need to reach offset + 8. */
808 int stack_chunk
809 = stack_space_to_allocate > (256 - 8 - 8)
810 ? (256 - 8 - 8) : stack_space_to_allocate;
811
812 fprintf (stream, "\tSUBU %s,%s,%d\n",
813 reg_names[MMIX_STACK_POINTER_REGNUM],
814 reg_names[MMIX_STACK_POINTER_REGNUM],
815 stack_chunk);
816 if (doing_dwarf)
817 {
818 cfa_offset += stack_chunk;
819 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
820 cfa_offset);
821 }
822 offset += stack_chunk;
823 stack_space_to_allocate -= stack_chunk;
824 }
825
826 fprintf (stream, "\tGET $255,rJ\n\tSTOU $255,%s,%d\n",
827 reg_names[MMIX_STACK_POINTER_REGNUM],
828 offset);
829 if (doing_dwarf)
830 dwarf2out_return_save ("", -cfa_offset + offset);
831 offset -= 8;
832 }
833 else if (MMIX_CFUN_HAS_LANDING_PAD)
834 offset -= 8;
835
836 if (MMIX_CFUN_HAS_LANDING_PAD)
837 {
838 /* Store the register defining the numbering of local registers, so
839 we know how long to unwind the register stack. */
840
841 empty_stack_frame = 0;
842
843 if (offset < 0)
844 {
845 /* Get 8 less than otherwise, since we need to reach offset + 8. */
846 int stack_chunk
847 = stack_space_to_allocate > (256 - 8 - 8)
848 ? (256 - 8 - 8) : stack_space_to_allocate;
849
850 fprintf (stream, "\tSUBU %s,%s,%d\n",
851 reg_names[MMIX_STACK_POINTER_REGNUM],
852 reg_names[MMIX_STACK_POINTER_REGNUM],
853 stack_chunk);
854 offset += stack_chunk;
855 stack_space_to_allocate -= stack_chunk;
856
857 if (doing_dwarf)
858 {
859 cfa_offset += stack_chunk;
860 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
861 cfa_offset);
862 }
863 }
864
865 /* We don't tell dwarf2 about this one; we just have it to unwind
866 the register stack at landing pads. FIXME: It's a kludge because
867 we can't describe the effect of the PUSHJ and PUSHGO insns on the
868 register stack at the moment. Best thing would be to handle it
869 like stack-pointer offsets. Better: some hook into dwarf2out.c
870 to produce DW_CFA_expression:s that specify the increment of rO,
871 and unwind it at eh_return (preferred) or at the landing pad.
872 Then saves to $0..$G-1 could be specified through that register. */
873
874 fprintf (stream, "\tGET $255,rO\n\tSTOU $255,%s,%d\n",
875 reg_names[MMIX_STACK_POINTER_REGNUM], offset);
876
877 offset -= 8;
878 }
879
880 /* After the return-address and the frame-pointer, we have the local
881 variables. They're the ones that may have an "unaligned" size. */
882 offset -= (locals_size + 7) & ~7;
883
884 /* Now store all registers that are global, i.e. not saved by the
885 register file machinery.
886
887 It is assumed that the frame-pointer is one of these registers, so it
888 is explicitly excluded in the count. */
889
890 for (regno = 255;
891 regno >= MMIX_FIRST_GLOBAL_REGNUM;
892 regno--)
893 if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
894 && regs_ever_live[regno] && ! call_used_regs[regno])
895 || IS_MMIX_EH_RETURN_DATA_REG (regno))
896 {
897 empty_stack_frame = 0;
898
899 if (offset < 0)
900 {
901 int stack_chunk;
902
903 /* Since the local variables go above, we may get a large
904 offset here. */
905 if (offset < -248)
906 {
907 /* We're not going to access the locals area in the
908 prologue, so we'll just silently subtract the slab we
909 will not access. */
910 stack_chunk =
911 stack_space_to_allocate > (256 - offset - 8)
912 ? (256 - offset - 8) : stack_space_to_allocate;
913
914 mmix_output_register_setting (stream, 255, stack_chunk, 1);
915 fprintf (stream, "\tSUBU %s,%s,$255\n",
916 reg_names[MMIX_STACK_POINTER_REGNUM],
917 reg_names[MMIX_STACK_POINTER_REGNUM]);
918
919 if (doing_dwarf)
920 {
921 cfa_offset += stack_chunk;
922 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
923 cfa_offset);
924 }
925 }
926 else
927 {
928 stack_chunk = stack_space_to_allocate > (256 - 8)
929 ? (256 - 8) : stack_space_to_allocate;
930
931 fprintf (stream, "\tSUBU %s,%s,%d\n",
932 reg_names[MMIX_STACK_POINTER_REGNUM],
933 reg_names[MMIX_STACK_POINTER_REGNUM], stack_chunk);
934 if (doing_dwarf)
935 {
936 cfa_offset += stack_chunk;
937 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
938 cfa_offset);
939 }
940 }
941
942 offset += stack_chunk;
943 stack_space_to_allocate -= stack_chunk;
944 }
945
946 fprintf (stream, "\tSTOU %s,%s,%d\n", reg_names[regno],
947 reg_names[MMIX_STACK_POINTER_REGNUM], offset);
948 if (doing_dwarf)
949 dwarf2out_reg_save ("", regno, -cfa_offset + offset);
950 offset -= 8;
951 }
952
953 /* Finally, allocate room for local vars (if they weren't allocated for
954 above) and outgoing args. This might be any number of bytes (well,
955 we assume it fits in a host-int).
956 Don't allocate (the return-address slot) if the stack frame is empty. */
957 if (stack_space_to_allocate && ! empty_stack_frame)
958 {
959 if (stack_space_to_allocate < 256)
960 {
961 fprintf (stream, "\tSUBU %s,%s,%d\n",
962 reg_names[MMIX_STACK_POINTER_REGNUM],
963 reg_names[MMIX_STACK_POINTER_REGNUM],
964 stack_space_to_allocate);
965 }
966 else
967 {
968 mmix_output_register_setting (stream, 255,
969 stack_space_to_allocate, 1);
970 fprintf (stream, "\tSUBU %s,%s,$255\n",
971 reg_names[MMIX_STACK_POINTER_REGNUM],
972 reg_names[MMIX_STACK_POINTER_REGNUM]);
973 }
974
975 if (doing_dwarf)
976 {
977 cfa_offset += stack_space_to_allocate;
978 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
979 cfa_offset);
980 }
981 }
982
983 /* We put the number of the highest saved register-file register in a
984 location convenient for the call-patterns to output. Note that we
985 don't tell dwarf2 about these registers, since it can't restore them
986 anyway. */
987 for (regno = MMIX_LAST_REGISTER_FILE_REGNUM;
988 regno >= 0;
989 regno--)
990 if ((regs_ever_live[regno] && !call_used_regs[regno])
991 || (regno == MMIX_FRAME_POINTER_REGNUM && frame_pointer_needed))
992 break;
993
994 mmix_highest_saved_stack_register = regno;
68cbb7e3 995}
996
997/* TARGET_ASM_FUNCTION_EPILOGUE. */
998
999void
1000mmix_target_asm_function_epilogue (stream, locals_size)
1001 FILE *stream;
1002 HOST_WIDE_INT locals_size;
1003
1004{
1005 int regno;
1006 int stack_space_to_deallocate
1007 = (current_function_outgoing_args_size
1008 + current_function_pretend_args_size
1009 + (int) locals_size + 8 + 7) & ~7;
1010
1011 /* The assumption that locals_size fits in an int is asserted in
1012 mmix_target_asm_function_prologue. */
1013
1014 /* The first address to access is beyond the outgoing_args area. */
1015 int offset = current_function_outgoing_args_size;
1016 int empty_stack_frame
1017 = (current_function_outgoing_args_size == 0
1018 && locals_size == 0
1019 && current_function_pretend_args_size == 0
1020 && ! MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS
1021 && ! MMIX_CFUN_HAS_LANDING_PAD);
1022
1023 /* Add the space for global non-register-stack registers.
1024 It is assumed that the frame-pointer register can be one of these
1025 registers, in which case it is excluded from the count when needed. */
1026 for (regno = 255;
1027 regno >= MMIX_FIRST_GLOBAL_REGNUM;
1028 regno--)
1029 if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
1030 && regs_ever_live[regno] && !call_used_regs[regno])
1031 || IS_MMIX_EH_RETURN_DATA_REG (regno))
1032 stack_space_to_deallocate += 8;
1033
1034 /* Add in the space for register stack-pointer. If so, always add room
1035 for the saved PC. */
1036 if (MMIX_CFUN_HAS_LANDING_PAD)
1037 stack_space_to_deallocate += 16;
1038 else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
1039 /* If we have a saved return-address slot, add it in. */
1040 stack_space_to_deallocate += 8;
1041
1042 /* Add in the frame-pointer. */
1043 if (frame_pointer_needed)
1044 stack_space_to_deallocate += 8;
1045
f0b228a5 1046 /* Make sure we don't get an unaligned stack. */
68cbb7e3 1047 if ((stack_space_to_deallocate % 8) != 0)
68435912 1048 internal_error ("stack frame not a multiple of octabyte: %d",
68cbb7e3 1049 stack_space_to_deallocate);
1050
1051 /* We will add back small offsets to the stack pointer as we go.
1052 First, we restore all registers that are global, i.e. not saved by
1053 the register file machinery. */
1054
1055 for (regno = MMIX_FIRST_GLOBAL_REGNUM;
1056 regno <= 255;
1057 regno++)
1058 if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
1059 && regs_ever_live[regno] && !call_used_regs[regno])
1060 || IS_MMIX_EH_RETURN_DATA_REG (regno))
1061 {
1062 empty_stack_frame = 0;
1063
1064 if (offset > 255)
1065 {
1066 if (offset > 65535)
1067 {
1068 /* There's better support for incrementing than
1069 decrementing, so we might be able to optimize this as
1070 we see a need. */
1071 mmix_output_register_setting (stream, 255, offset, 1);
1072 fprintf (stream, "\tADDU %s,%s,$255\n",
1073 reg_names[MMIX_STACK_POINTER_REGNUM],
1074 reg_names[MMIX_STACK_POINTER_REGNUM]);
1075 }
1076 else
1077 fprintf (stream, "\tINCL %s,%d\n",
1078 reg_names[MMIX_STACK_POINTER_REGNUM], offset);
1079
1080 stack_space_to_deallocate -= offset;
1081 offset = 0;
1082 }
1083
1084 fprintf (stream, "\tLDOU %s,%s,%d\n",
1085 reg_names[regno],
1086 reg_names[MMIX_STACK_POINTER_REGNUM],
1087 offset);
1088 offset += 8;
1089 }
1090
1091 /* Here is where the local variables were. As in the prologue, they
1092 might be of an unaligned size. */
1093 offset += (locals_size + 7) & ~7;
1094
1095
1096 /* The saved register stack pointer is just below the frame-pointer
1097 register. We don't need to restore it "manually"; the POP
1098 instruction does that. */
1099 if (MMIX_CFUN_HAS_LANDING_PAD)
1100 offset += 16;
1101 else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
1102 /* The return-address slot is just below the frame-pointer register.
1103 We don't need to restore it because we don't really use it. */
1104 offset += 8;
1105
1106 /* Get back the old frame-pointer-value. */
1107 if (frame_pointer_needed)
1108 {
1109 empty_stack_frame = 0;
1110
1111 if (offset > 255)
1112 {
1113 if (offset > 65535)
1114 {
1115 /* There's better support for incrementing than
1116 decrementing, so we might be able to optimize this as
1117 we see a need. */
1118 mmix_output_register_setting (stream, 255, offset, 1);
1119 fprintf (stream, "\tADDU %s,%s,$255\n",
1120 reg_names[MMIX_STACK_POINTER_REGNUM],
1121 reg_names[MMIX_STACK_POINTER_REGNUM]);
1122 }
1123 else
1124 fprintf (stream, "\tINCL %s,%d\n",
1125 reg_names[MMIX_STACK_POINTER_REGNUM], offset);
1126
1127 stack_space_to_deallocate -= offset;
1128 offset = 0;
1129 }
1130
1131 fprintf (stream, "\tLDOU %s,%s,%d\n",
1132 reg_names[MMIX_FRAME_POINTER_REGNUM],
1133 reg_names[MMIX_STACK_POINTER_REGNUM],
1134 offset);
1135 offset += 8;
1136 }
1137
1138 /* Do not deallocate the return-address slot if the stack frame is
1139 empty, because then it was never allocated. */
1140 if (! empty_stack_frame)
1141 {
1142 /* We do not need to restore pretended incoming args, just add
1143 back offset to sp. */
1144 if (stack_space_to_deallocate > 65535)
1145 {
1146 /* There's better support for incrementing than decrementing, so
1147 we might be able to optimize this as we see a need. */
1148 mmix_output_register_setting (stream, 255,
1149 stack_space_to_deallocate, 1);
1150 fprintf (stream, "\tADDU %s,%s,$255\n",
1151 reg_names[MMIX_STACK_POINTER_REGNUM],
1152 reg_names[MMIX_STACK_POINTER_REGNUM]);
1153 }
1154 else
1155 fprintf (stream, "\tINCL %s,%d\n",
1156 reg_names[MMIX_STACK_POINTER_REGNUM],
1157 stack_space_to_deallocate);
1158 }
1159
1160 if (current_function_calls_eh_return)
1161 /* Adjustment the (normal) stack-pointer to that of the receiver.
1162 FIXME: It would be nice if we could also adjust the register stack
1163 here, but we need to express it through DWARF 2 too. */
1164 fprintf (stream, "\tADDU %s,%s,%s\n",
1165 reg_names [MMIX_STACK_POINTER_REGNUM],
1166 reg_names [MMIX_STACK_POINTER_REGNUM],
1167 reg_names [MMIX_EH_RETURN_STACKADJ_REGNUM]);
1168
1169 /* The extra \n is so we have a blank line between the assembly code of
1170 separate functions. */
1171 fprintf (stream, "\tPOP %d,0\n\n",
1172 (! TARGET_ABI_GNU
1173 && current_function_return_rtx != NULL
1174 && ! current_function_returns_struct)
1175 ? (GET_CODE (current_function_return_rtx) == PARALLEL
1176 ? GET_NUM_ELEM (XVEC (current_function_return_rtx, 0)) : 1)
1177 : 0);
1178}
1179
1180/* ASM_OUTPUT_MI_THUNK. */
1181
1182void
1183mmix_asm_output_mi_thunk (stream, fndecl, delta, func)
1184 FILE * stream;
1185 tree fndecl ATTRIBUTE_UNUSED;
1186 int delta;
1187 tree func;
1188{
1189 /* If you define STRUCT_VALUE to 0, rather than use STRUCT_VALUE_REGNUM,
1190 (i.e. pass location of structure to return as invisible first
1191 argument) you need to tweak this code too. */
1192 const char *regname = reg_names[MMIX_FIRST_INCOMING_ARG_REGNUM];
1193
1194 if (delta >= 0 && delta < 65536)
1195 asm_fprintf (stream, "\tINCL %s,%d\n", delta, regname);
1196 else if (delta < 0 && delta >= -255)
1197 asm_fprintf (stream, "\tSUBU %s,%s,%d\n", regname, regname, -delta);
1198 else
1199 {
1200 mmix_output_register_setting (stream, 255, delta, 1);
1201 asm_fprintf (stream, "\tADDU %s,%s,$255\n", regname, regname);
1202 }
1203
1204 fprintf (stream, "\tJMP ");
1205 assemble_name (stream, XSTR (XEXP (DECL_RTL (func), 0), 0));
1206 fprintf (stream, "\n");
1207}
1208
1209/* FUNCTION_PROFILER. */
1210
1211void
1212mmix_function_profiler (stream, labelno)
1213 FILE *stream ATTRIBUTE_UNUSED;
1214 int labelno ATTRIBUTE_UNUSED;
1215{
1216 sorry ("function_profiler support for MMIX");
1217}
1218
68cbb7e3 1219/* SETUP_INCOMING_VARARGS. */
1220
1221void
1222mmix_setup_incoming_varargs (args_so_farp, mode, vartype, pretend_sizep,
1223 second_time)
1224 CUMULATIVE_ARGS * args_so_farp;
1225 enum machine_mode mode;
1226 tree vartype;
1227 int * pretend_sizep;
1228 int second_time ATTRIBUTE_UNUSED;
1229{
1230 /* For stdarg, the last named variable has been handled, but
1231 args_so_farp has not been advanced for it. For varargs, the current
1232 argument is to be counted to the anonymous ones. */
1233 if (current_function_stdarg)
1234 {
1235 if (args_so_farp->regs + 1 < MMIX_MAX_ARGS_IN_REGS)
1236 *pretend_sizep
1237 = (MMIX_MAX_ARGS_IN_REGS - (args_so_farp->regs + 1)) * 8;
1238 }
1239 else if (current_function_varargs)
1240 {
1241 if (args_so_farp->regs < MMIX_MAX_ARGS_IN_REGS)
1242 *pretend_sizep
1243 = (MMIX_MAX_ARGS_IN_REGS - args_so_farp->regs) * 8;
1244
1245 /* For varargs, we get here when we see the last named parameter,
1246 which will actually be passed on stack. So make the next call
1247 (there will be one) to FUNCTION_ARG return 0, to count it on
1248 stack, so va_arg for it will get right. FIXME: The GCC core
1249 should provide TRT. */
1250 args_so_farp->now_varargs = 1;
1251 }
1252 else
68435912 1253 internal_error ("neither varargs or stdarg in mmix_setup_incoming_varargs");
68cbb7e3 1254
1255
1256 /* We assume that one argument takes up one register here. That should
1257 be true until we start messing with multi-reg parameters. */
1258 if ((7 + (MMIX_FUNCTION_ARG_SIZE (mode, vartype))) / 8 != 1)
1259 internal_error ("MMIX Internal: Last named vararg would not fit in a register");
1260}
1261
1262/* EXPAND_BUILTIN_VA_ARG. */
1263
1264/* This is modified from the "standard" implementation of va_arg: read the
1265 value from the current (padded) address and increment by the (padded)
1266 size. The difference for MMIX is that if the type is
1267 pass-by-reference, then perform an indirection. */
1268
1269rtx
1270mmix_expand_builtin_va_arg (valist, type)
1271 tree valist;
1272 tree type;
1273{
1274 tree addr_tree, t;
1275 HOST_WIDE_INT align;
1276 HOST_WIDE_INT rounded_size;
1277 rtx addr;
1278
1279 /* Compute the rounded size of the type. */
1280 align = PARM_BOUNDARY / BITS_PER_UNIT;
1281 rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
1282
1283 /* Get AP. */
1284 addr_tree = valist;
1285
1286 if (AGGREGATE_TYPE_P (type)
1287 && GET_MODE_UNIT_SIZE (TYPE_MODE (type)) < 8
1288 && GET_MODE_UNIT_SIZE (TYPE_MODE (type)) != 0)
1289 {
1290 /* Adjust for big-endian the location of aggregates passed in a
1291 register, but where the aggregate is accessed in a shorter mode
1292 than the natural register mode (i.e. it is accessed as SFmode(?),
1293 SImode, HImode or QImode rather than DImode or DFmode(?)). FIXME:
1294 Or should we adjust the mode in which the aggregate is read, to be
1295 a register size mode? (Hum, nah, a small offset is generally
1296 cheaper than a wider memory access on MMIX.) */
1297 addr_tree
1298 = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
1299 build_int_2 ((BITS_PER_WORD / BITS_PER_UNIT)
1300 - GET_MODE_UNIT_SIZE (TYPE_MODE (type)), 0));
1301 }
1302 else
1303 {
1304 HOST_WIDE_INT adj;
1305 adj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT;
1306 if (rounded_size > align)
1307 adj = rounded_size;
1308
1309 addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
1310 build_int_2 (rounded_size - adj, 0));
1311
1312 /* If this type is larger than what fits in a register, then it is
1313 passed by reference. */
1314 if (rounded_size > BITS_PER_WORD / BITS_PER_UNIT)
1315 {
1316 tree type_ptr = build_pointer_type (type);
1317 addr_tree = build1 (INDIRECT_REF, type_ptr, addr_tree);
1318 }
1319 }
1320
1321 addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
1322 addr = copy_to_reg (addr);
1323
1324 /* Compute new value for AP. For MMIX, it is always advanced by the
1325 size of a register. */
1326 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1327 build (PLUS_EXPR, TREE_TYPE (valist), valist,
1328 build_int_2 (BITS_PER_WORD / BITS_PER_UNIT, 0)));
1329 TREE_SIDE_EFFECTS (t) = 1;
1330 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1331
1332 return addr;
1333}
1334
1335/* TRAMPOLINE_SIZE. */
1336/* Four 4-byte insns plus two 8-byte values. */
1337int mmix_trampoline_size = 32;
1338
1339
1340/* TRAMPOLINE_TEMPLATE. */
1341
1342void
1343mmix_trampoline_template (stream)
1344 FILE * stream;
1345{
1346 /* Read a value from to static-chain, jump somewhere. The static chain
1347 is stored at offset 16, and the function address is stored at offset
1348 24. */
1349 /* FIXME: GCC copies this using *intsize* (tetra), when it should use
1350 register size (octa). */
1351 fprintf (stream, "\tGETA $255,1F\n\t");
1352 fprintf (stream, "LDOU %s,$255,0\n\t",
1353 reg_names[MMIX_STATIC_CHAIN_REGNUM]);
1354 fprintf (stream, "LDOU $255,$255,8\n\t");
1355 fprintf (stream, "GO $255,$255,0\n");
1356 fprintf (stream, "1H\tOCTA 0\n\t");
1357 fprintf (stream, "OCTA 0\n");
1358}
1359
1360/* INITIALIZE_TRAMPOLINE. */
1361/* Set the static chain and function pointer field in the trampoline.
1362 We also SYNCID here to be sure (doesn't matter in the simulator, but
1363 some day it will). */
1364
1365void
1366mmix_initialize_trampoline (trampaddr, fnaddr, static_chain)
1367 rtx trampaddr;
1368 rtx fnaddr;
1369 rtx static_chain;
1370{
1371 emit_move_insn (gen_rtx_MEM (DImode, plus_constant (trampaddr, 16)),
1372 static_chain);
1373 emit_move_insn (gen_rtx_MEM (DImode,
1374 plus_constant (trampaddr, 24)),
1375 fnaddr);
1376 emit_insn (gen_sync_icache (validize_mem (gen_rtx_MEM (DImode,
1377 trampaddr)),
1378 GEN_INT (mmix_trampoline_size - 1)));
1379}
1380
1381/* We must exclude constant addresses that have an increment that is not a
1382 multiple of four bytes because of restrictions of the GETA
f0b228a5 1383 instruction, unless TARGET_BASE_ADDRESSES. */
68cbb7e3 1384
1385int
1386mmix_constant_address_p (x)
1387 rtx x;
1388{
1389 RTX_CODE code = GET_CODE (x);
1390 int addend = 0;
f0b228a5 1391 /* When using "base addresses", anything constant goes. */
1392 int constant_ok = TARGET_BASE_ADDRESSES != 0;
68cbb7e3 1393
1394 if (code == LABEL_REF || code == SYMBOL_REF)
1395 return 1;
1396
1397 if (code == CONSTANT_P_RTX || code == HIGH)
1398 /* FIXME: Don't know how to dissect these. Avoid them for now. */
f0b228a5 1399 return constant_ok;
68cbb7e3 1400
1401 switch (code)
1402 {
1403 case LABEL_REF:
1404 case SYMBOL_REF:
1405 return 1;
1406
68cbb7e3 1407 case CONSTANT_P_RTX:
1408 case HIGH:
f0b228a5 1409 /* FIXME: Don't know how to dissect these. Avoid them for now,
1410 except we know they're constants. */
1411 return constant_ok;
68cbb7e3 1412
1413 case CONST_INT:
1414 addend = INTVAL (x);
1415 break;
1416
1417 case CONST_DOUBLE:
1418 if (GET_MODE (x) != VOIDmode)
1419 /* Strange that we got here. FIXME: Check if we do. */
f0b228a5 1420 return constant_ok;
68cbb7e3 1421 addend = CONST_DOUBLE_LOW (x);
1422 break;
1423
1424 case CONST:
1425 /* Note that expressions with arithmetic on forward references don't
1426 work in mmixal. People using gcc assembly code with mmixal might
1427 need to move arrays and such to before the point of use. */
1428 if (GET_CODE (XEXP (x, 0)) == PLUS)
1429 {
1430 rtx x0 = XEXP (XEXP (x, 0), 0);
1431 rtx x1 = XEXP (XEXP (x, 0), 1);
1432
1433 if ((GET_CODE (x0) == SYMBOL_REF
1434 || GET_CODE (x0) == LABEL_REF)
1435 && (GET_CODE (x1) == CONST_INT
1436 || (GET_CODE (x1) == CONST_DOUBLE
1437 && GET_MODE (x1) == VOIDmode)))
1438 addend = mmix_intval (x1);
1439 else
f0b228a5 1440 return constant_ok;
68cbb7e3 1441 }
1442 else
f0b228a5 1443 return constant_ok;
68cbb7e3 1444 break;
1445
1446 default:
1447 return 0;
1448 }
1449
f0b228a5 1450 return constant_ok || (addend & 3) == 0;
68cbb7e3 1451}
1452
1453/* Return 1 if the address is OK, otherwise 0.
1454 Used by GO_IF_LEGITIMATE_ADDRESS. */
1455
1456int
1457mmix_legitimate_address (mode, x, strict_checking)
1458 enum machine_mode mode ATTRIBUTE_UNUSED;
1459 rtx x;
1460 int strict_checking;
1461{
1462#define MMIX_REG_OK(X) \
1463 ((strict_checking \
1464 && (REGNO (X) <= MMIX_LAST_GENERAL_REGISTER \
1465 || (reg_renumber[REGNO (X)] > 0 \
1466 && reg_renumber[REGNO (X)] <= MMIX_LAST_GENERAL_REGISTER))) \
1467 || (!strict_checking \
1468 && (REGNO (X) <= MMIX_LAST_GENERAL_REGISTER \
1469 || REGNO (X) >= FIRST_PSEUDO_REGISTER \
1470 || REGNO (X) == ARG_POINTER_REGNUM)))
1471
1472 /* We only accept:
1473 (mem reg)
1474 (mem (plus reg reg))
f0b228a5 1475 (mem (plus reg 0..255)).
1476 unless TARGET_BASE_ADDRESSES, in which case we accept all
1477 (mem constant_address) too. */
68cbb7e3 1478
1479
1480 /* (mem reg) */
1481 if (REG_P (x) && MMIX_REG_OK (x))
1482 return 1;
1483
1484 if (GET_CODE(x) == PLUS)
1485 {
1486 rtx x1 = XEXP (x, 0);
1487 rtx x2 = XEXP (x, 1);
1488
1489 /* Try swapping the order. FIXME: Do we need this? */
1490 if (! REG_P (x1))
1491 {
1492 rtx tem = x1;
1493 x1 = x2;
1494 x2 = tem;
1495 }
1496
f0b228a5 1497 /* (mem (plus (reg?) (?))) */
68cbb7e3 1498 if (!REG_P (x1) || !MMIX_REG_OK (x1))
f0b228a5 1499 return TARGET_BASE_ADDRESSES && mmix_constant_address_p (x);
68cbb7e3 1500
f0b228a5 1501 /* (mem (plus (reg) (reg?))) */
68cbb7e3 1502 if (REG_P (x2) && MMIX_REG_OK (x2))
1503 return 1;
1504
f0b228a5 1505 /* (mem (plus (reg) (0..255?))) */
68cbb7e3 1506 if (GET_CODE (x2) == CONST_INT
1507 && CONST_OK_FOR_LETTER_P (INTVAL (x2), 'I'))
1508 return 1;
f0b228a5 1509
1510 return 0;
68cbb7e3 1511 }
1512
f0b228a5 1513 return TARGET_BASE_ADDRESSES && mmix_constant_address_p (x);
68cbb7e3 1514}
1515
1516/* LEGITIMATE_CONSTANT_P. */
1517
1518int
1519mmix_legitimate_constant_p (x)
1520 rtx x;
1521{
1522 RTX_CODE code = GET_CODE (x);
1523
1524 /* We must allow any number due to the way the cse passes works; if we
1525 do not allow any number here, general_operand will fail, and insns
1526 will fatally fail recognition instead of "softly". */
1527 if (code == CONST_INT || code == CONST_DOUBLE)
1528 return 1;
1529
1530 return CONSTANT_ADDRESS_P (x);
1531}
1532
1533/* SELECT_CC_MODE. */
1534
1535enum machine_mode
1536mmix_select_cc_mode (op, x, y)
1537 RTX_CODE op;
1538 rtx x;
1539 rtx y ATTRIBUTE_UNUSED;
1540{
1541 /* We use CCmode, CC_UNSmode, CC_FPmode, CC_FPEQmode and CC_FUNmode to
1542 output different compare insns. Note that we do not check the
1543 validity of the comparison here. */
1544
1545 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1546 {
1547 if (op == ORDERED || op == UNORDERED || op == UNGE
1548 || op == UNGT || op == UNLE || op == UNLT)
1549 return CC_FUNmode;
1550
1551 if (op == EQ || op == NE)
1552 return CC_FPEQmode;
1553
1554 return CC_FPmode;
1555 }
1556
1557 if (op == GTU || op == LTU || op == GEU || op == LEU)
1558 return CC_UNSmode;
1559
1560 return CCmode;
1561}
1562
1563/* CANONICALIZE_COMPARISON.
1564 FIXME: Check if the number adjustments trig. */
1565
1566void
1567mmix_canonicalize_comparison (codep, op0p, op1p)
1568 RTX_CODE * codep;
1569 rtx * op0p ATTRIBUTE_UNUSED;
1570 rtx * op1p;
1571{
1572 /* Change -1 to zero, if possible. */
1573 if ((*codep == LE || *codep == GT)
1574 && GET_CODE (*op1p) == CONST_INT
1575 && *op1p == constm1_rtx)
1576 {
1577 *codep = *codep == LE ? LT : GE;
1578 *op1p = const0_rtx;
1579 }
1580
1581 /* Fix up 256 to 255, if possible. */
1582 if ((*codep == LT || *codep == LTU || *codep == GE || *codep == GEU)
1583 && GET_CODE (*op1p) == CONST_INT
1584 && INTVAL (*op1p) == 256)
1585 {
1586 /* FIXME: Remove when I know this trigs. */
68435912 1587 fatal_insn ("oops, not debugged; fixing up value:", *op1p);
68cbb7e3 1588 *codep = *codep == LT ? LE : *codep == LTU ? LEU : *codep
1589 == GE ? GT : GTU;
1590 *op1p = GEN_INT (255);
1591 }
1592}
1593
1594/* REVERSIBLE_CC_MODE. */
1595
1596int
1597mmix_reversible_cc_mode (mode)
1598 enum machine_mode mode;
1599{
1600 /* That is, all integer and the EQ, NE, ORDERED and UNORDERED float
1601 cmpares. */
1602 return mode != CC_FPmode;
1603}
1604
1605/* DEFAULT_RTX_COSTS. */
1606
1607int
1608mmix_rtx_cost_recalculated (x, code, outer_code, costp)
1609 rtx x ATTRIBUTE_UNUSED;
1610 RTX_CODE code ATTRIBUTE_UNUSED;
1611 RTX_CODE outer_code ATTRIBUTE_UNUSED;
1612 int *costp ATTRIBUTE_UNUSED;
1613{
1614 /* For the time being, this is just a stub and we'll accept the
1615 generic calculations, until we can do measurements, at least.
1616 Say we did not modify any calculated costs. */
1617 return 0;
1618}
1619
1620/* ADDRESS_COST. */
1621
1622int
1623mmix_address_cost (addr)
1624 rtx addr ATTRIBUTE_UNUSED;
1625{
1626 /* There's no difference in the address costs and we have lots of
1627 registers. Some targets use constant 0, many others use 1 to say
1628 this. Let's start with 1. */
1629 return 1;
1630}
1631
1632/* REGISTER_MOVE_COST. */
1633
1634int
1635mmix_register_move_cost (mode, from, to)
1636 enum machine_mode mode ATTRIBUTE_UNUSED;
1637 enum reg_class from;
1638 enum reg_class to;
1639{
1640 return (from == GENERAL_REGS && from == to) ? 2 : 3;
1641}
1642
1643/* Note that we don't have a TEXT_SECTION_ASM_OP, because it has to be a
1644 compile-time constant; it's used in an asm in crtstuff.c, compiled for
1645 the target. */
1646
1647/* DATA_SECTION_ASM_OP. */
1648
1649const char *
1650mmix_data_section_asm_op ()
1651{
1652 return "\t.data ! mmixal:= 8H LOC 9B";
1653}
1654
1655/* SELECT_SECTION.
1656 The meat is from elfos.h, which we will eventually consider using. */
1657
1658void
1659mmix_select_section (decl, reloc, align)
1660 tree decl;
1661 int reloc;
1662 int align ATTRIBUTE_UNUSED;
1663{
1664 if (TREE_CODE (decl) == STRING_CST)
1665 {
1666 if (! flag_writable_strings)
1667 const_section ();
1668 else
1669 data_section ();
1670 }
1671 else if (TREE_CODE (decl) == VAR_DECL)
1672 {
1673 if ((flag_pic && reloc)
1674 || !TREE_READONLY (decl) || TREE_SIDE_EFFECTS (decl)
1675 || !DECL_INITIAL (decl)
1676 || (DECL_INITIAL (decl) != error_mark_node
1677 && !TREE_CONSTANT (DECL_INITIAL (decl))))
1678 data_section ();
1679 else
1680 const_section ();
1681 }
1682 else if (TREE_CODE (decl) == CONSTRUCTOR)
1683 {
1684 if ((flag_pic && reloc)
1685 || !TREE_READONLY (decl) || TREE_SIDE_EFFECTS (decl)
1686 || ! TREE_CONSTANT (decl))
1687 data_section ();
1688 else
1689 const_section ();
1690 }
1691 else
1692 const_section ();
1693}
1694
1695/* ENCODE_SECTION_INFO. */
1696
1697void
1698mmix_encode_section_info (decl)
1699 tree decl;
1700{
1701 /* Test for an external declaration, and do nothing if it is one. */
1702 if ((TREE_CODE (decl) == VAR_DECL
91009d64 1703 && (DECL_EXTERNAL (decl) || TREE_PUBLIC (decl)))
1704 || (TREE_CODE (decl) == FUNCTION_DECL && TREE_PUBLIC (decl)))
68cbb7e3 1705 ;
1706 else if (DECL_P (decl))
1707 {
1708 /* For non-visible declarations, add a "@" prefix, which we skip
1709 when the label is output. If the label does not have this
f0b228a5 1710 prefix, a ":" is output if -mtoplevel-symbols.
68cbb7e3 1711
1712 Note that this does not work for data that is declared extern and
1713 later defined as static. If there's code in between, that code
f0b228a5 1714 will refer to the extern declaration, and vice versa. This just
1715 means that when -mtoplevel-symbols is in use, we can just handle
1716 well-behaved ISO-compliant code. */
68cbb7e3 1717
1718 const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
1719 int len = strlen (str);
1720 char *newstr;
1721
f0b228a5 1722 /* Why is the return type of ggc_alloc_string const? */
1723 newstr = (char *) ggc_alloc_string ("", len + 1);
68cbb7e3 1724
1725 strcpy (newstr + 1, str);
1726 *newstr = '@';
1727 XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
1728 }
1729
f0b228a5 1730 /* Set SYMBOL_REF_FLAG for things that we want to access with GETA. We
1731 may need different options to reach for different things with GETA.
1732 For now, functions and things we know or have been told are constant. */
1733 if (TREE_CODE (decl) == FUNCTION_DECL
1734 || TREE_CONSTANT (decl)
1735 || (TREE_CODE (decl) == VAR_DECL
1736 && TREE_READONLY (decl)
1737 && !TREE_SIDE_EFFECTS (decl)
1738 && (!DECL_INITIAL (decl)
1739 || TREE_CONSTANT (DECL_INITIAL (decl)))))
1740 {
1741 rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
1742 ? TREE_CST_RTL (decl) : DECL_RTL (decl));
1743 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
1744 }
68cbb7e3 1745}
1746
1747/* STRIP_NAME_ENCODING. */
1748
1749const char *
1750mmix_strip_name_encoding (name)
1751 const char *name;
1752{
1753 for (; (*name == '@' || *name == '*'); name++)
1754 ;
1755
1756 return name;
1757}
1758
1759/* UNIQUE_SECTION.
1760 The meat is from elfos.h, which we should consider using. */
1761
1762void
1763mmix_unique_section (decl, reloc)
1764 tree decl;
1765 int reloc;
1766{
1767 int len;
1768 int sec;
1769 const char *name;
1770 char *string;
1771 const char *prefix;
25037517 1772 static const char *const prefixes[4][2] =
68cbb7e3 1773 {
1774 { ".text.", ".gnu.linkonce.t." },
1775 { ".rodata.", ".gnu.linkonce.r." },
1776 { ".data.", ".gnu.linkonce.d." },
1777 { ".bss.", ".gnu.linkonce.b." }
1778 };
1779
1780 if (TREE_CODE (decl) == FUNCTION_DECL)
1781 sec = 0;
1782 else if (DECL_INITIAL (decl) == 0
1783 || DECL_INITIAL (decl) == error_mark_node)
1784 sec = 3;
1785 else if (DECL_READONLY_SECTION (decl, reloc))
1786 sec = 1;
1787 else
1788 sec = 2;
1789
1790 name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
1791 /* Strip off any encoding in name. */
1792 STRIP_NAME_ENCODING (name, name);
1793 prefix = prefixes[sec][DECL_ONE_ONLY (decl)];
1794 len = strlen (name) + strlen (prefix);
1795 string = alloca (len + 1);
1796
1797 sprintf (string, "%s%s", prefix, name);
1798
1799 DECL_SECTION_NAME (decl) = build_string (len, string);
1800}
1801
1802/* ASM_FILE_START. */
1803
1804void
1805mmix_asm_file_start (stream)
1806 FILE * stream;
1807{
1808 /* We just emit a little comment for the time being. FIXME: Perhaps add
1809 -mstandalone and some segment and prefix setup here. */
1810 ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename);
1811
1812 fprintf (stream, "! mmixal:= 8H LOC Data_Section\n");
1813
1814 /* Make sure each file starts with the text section. */
1815 text_section ();
1816}
1817
1818/* ASM_FILE_END. */
1819
1820void
1821mmix_asm_file_end (stream)
1822 FILE * stream ATTRIBUTE_UNUSED;
1823{
1824 /* Make sure each file ends with the data section. */
1825 data_section ();
1826}
1827
68cbb7e3 1828/* ASM_OUTPUT_SOURCE_FILENAME. */
1829
1830void
1831mmix_asm_output_source_filename (stream, name)
1832 FILE * stream;
1833 const char * name;
1834{
1835 fprintf (stream, "# 1 ");
1836 OUTPUT_QUOTED_STRING (stream, name);
1837 fprintf (stream, "\n");
1838}
1839
1840/* OUTPUT_QUOTED_STRING. */
1841
1842void
1843mmix_output_quoted_string (stream, string, length)
1844 FILE * stream;
1845 const char * string;
1846 int length;
1847{
1848 const char * string_end = string + length;
25037517 1849 static const char *const unwanted_chars = "\"[]\\";
68cbb7e3 1850
1851 /* Output "any character except newline and double quote character". We
1852 play it safe and avoid all control characters too. We also do not
1853 want [] as characters, should input be passed through m4 with [] as
1854 quotes. Further, we avoid "\", because the GAS port handles it as a
1855 quoting character. */
1856 while (string < string_end)
1857 {
1858 if (*string
1859 && (unsigned char) *string < 128
1860 && !ISCNTRL (*string)
1861 && strchr (unwanted_chars, *string) == NULL)
1862 {
1863 fputc ('"', stream);
1864 while (*string
1865 && (unsigned char) *string < 128
1866 && !ISCNTRL (*string)
1867 && strchr (unwanted_chars, *string) == NULL
1868 && string < string_end)
1869 {
1870 fputc (*string, stream);
1871 string++;
1872 }
1873 fputc ('"', stream);
1874 if (string < string_end)
1875 fprintf (stream, ",");
1876 }
1877 if (string < string_end)
1878 {
1879 fprintf (stream, "#%x", *string & 255);
1880 string++;
1881 if (string < string_end)
1882 fprintf (stream, ",");
1883 }
1884 }
1885}
1886
1887/* ASM_OUTPUT_SOURCE_LINE. */
1888
1889void
1890mmix_asm_output_source_line (stream, lineno)
1891 FILE * stream;
1892 int lineno;
1893{
1894 fprintf (stream, "# %d ", lineno);
1895 OUTPUT_QUOTED_STRING (stream, main_input_filename);
1896 fprintf (stream, "\n");
1897}
1898
58356836 1899/* Target hook for assembling integer objects. Use mmix_print_operand
1900 for WYDE and TETRA. Use mmix_output_octa to output 8-byte
1901 CONST_DOUBLEs. */
68cbb7e3 1902
58356836 1903static bool
1904mmix_assemble_integer (x, size, aligned_p)
1905 rtx x;
1906 unsigned int size;
1907 int aligned_p;
68cbb7e3 1908{
58356836 1909 if (aligned_p)
1910 switch (size)
1911 {
4f4e478d 1912 /* We handle a limited number of types of operands in here. But
1913 that's ok, because we can punt to generic functions. We then
1914 pretend that we don't emit aligned data is needed, so the usual
1915 .pseudo syntax is used (which work for aligned data too). We
1916 actually *must* do that, since we say we don't have simple
1917 aligned pseudos, causing this function to be called. We just
1918 try and keep as much compatibility as possible with mmixal
1919 syntax for normal cases (i.e. without GNU extensions and C
1920 only). */
58356836 1921 case 1:
4f4e478d 1922 if (GET_CODE (x) != CONST_INT)
1923 {
1924 aligned_p = 0;
1925 break;
1926 }
58356836 1927 fputs ("\tBYTE\t", asm_out_file);
1928 mmix_print_operand (asm_out_file, x, 'B');
1929 fputc ('\n', asm_out_file);
1930 return true;
1931
1932 case 2:
4f4e478d 1933 if (GET_CODE (x) != CONST_INT)
1934 {
1935 aligned_p = 0;
1936 break;
1937 }
58356836 1938 fputs ("\tWYDE\t", asm_out_file);
1939 mmix_print_operand (asm_out_file, x, 'W');
1940 fputc ('\n', asm_out_file);
1941 return true;
1942
1943 case 4:
4f4e478d 1944 if (GET_CODE (x) != CONST_INT && GET_CODE (x) != SYMBOL_REF)
1945 {
1946 aligned_p = 0;
1947 break;
1948 }
58356836 1949 fputs ("\tTETRA\t", asm_out_file);
1950 mmix_print_operand (asm_out_file, x, 'L');
1951 fputc ('\n', asm_out_file);
1952 return true;
1953
1954 case 8:
1955 if (GET_CODE (x) == CONST_DOUBLE)
4f4e478d 1956 /* We don't get here anymore for CONST_DOUBLE, because DImode
1957 isn't expressed as CONST_DOUBLE, and DFmode is handled
1958 elsewhere. */
1959 abort ();
1960 assemble_integer_with_op ("\tOCTA\t", x);
58356836 1961 return true;
1962 }
1963 return default_assemble_integer (x, size, aligned_p);
68cbb7e3 1964}
1965
1966/* ASM_OUTPUT_ASCII. */
1967
1968void
1969mmix_asm_output_ascii (stream, string, length)
1970 FILE *stream;
1971 const char *string;
1972 int length;
1973{
1974 while (length > 0)
1975 {
1976 int chunk_size = length > 60 ? 60 : length;
1977 fprintf (stream, "\tBYTE ");
1978 mmix_output_quoted_string (stream, string, chunk_size);
1979 string += chunk_size;
1980 length -= chunk_size;
1981 fprintf (stream, "\n");
1982 }
1983}
1984
1985/* ASM_OUTPUT_ALIGNED_COMMON. */
1986
1987void
1988mmix_asm_output_aligned_common (stream, name, size, align)
1989 FILE *stream;
1990 const char *name;
1991 int size;
1992 int align;
1993{
1994 /* This is mostly the elfos.h one. There doesn't seem to be a way to
1995 express this in a mmixal-compatible way. */
1996 fprintf (stream, "\t.comm\t");
1997 assemble_name (stream, name);
1998 fprintf (stream, ",%u,%u ! mmixal-incompatible COMMON\n",
1999 size, align / BITS_PER_UNIT);
2000}
2001
2002/* ASM_OUTPUT_ALIGNED_LOCAL. */
2003
2004void
2005mmix_asm_output_aligned_local (stream, name, size, align)
2006 FILE * stream;
2007 const char * name;
2008 int size;
2009 int align;
2010{
2011 data_section ();
2012
2013 ASM_OUTPUT_ALIGN (stream, exact_log2 (align/BITS_PER_UNIT));
2014 assemble_name (stream, name);
2015 fprintf (stream, "\tLOC @+%d\n", size);
2016}
2017
2018/* ASM_OUTPUT_LABEL. */
2019
2020void
2021mmix_asm_output_label (stream, name)
2022 FILE *stream;
2023 const char * name;
2024{
2025 assemble_name (stream, name);
2026 fprintf (stream, "\tIS @\n");
2027}
2028
2029/* ASM_DECLARE_REGISTER_GLOBAL. */
2030
2031void
2032mmix_asm_declare_register_global (stream, decl, regno, name)
2033 FILE *stream ATTRIBUTE_UNUSED;
2034 tree decl ATTRIBUTE_UNUSED;
2035 int regno ATTRIBUTE_UNUSED;
2036 const char *name ATTRIBUTE_UNUSED;
2037{
2038 /* Nothing to do here, but there *will* be, therefore the framework is
2039 here. */
2040}
2041
2042/* ASM_GLOBALIZE_LABEL. */
2043
2044void
2045mmix_asm_globalize_label (stream, name)
2046 FILE * stream ATTRIBUTE_UNUSED;
2047 const char * name ATTRIBUTE_UNUSED;
2048{
2049 asm_fprintf (stream, "\t.global ");
2050 assemble_name (stream, name);
2051 putc ('\n', stream);
2052}
2053
2054/* ASM_WEAKEN_LABEL. */
2055
2056void
2057mmix_asm_weaken_label (stream, name)
2058 FILE * stream ATTRIBUTE_UNUSED;
2059 const char * name ATTRIBUTE_UNUSED;
2060{
2061 asm_fprintf (stream, "\t.weak ");
2062 assemble_name (stream, name);
2063 asm_fprintf (stream, " ! mmixal-incompatible\n");
2064}
2065
2066/* MAKE_DECL_ONE_ONLY. */
2067
2068void
2069mmix_make_decl_one_only (decl)
2070 tree decl;
2071{
2072 DECL_WEAK (decl) = 1;
2073}
2074
2075/* ASM_OUTPUT_LABELREF.
2076 Strip GCC's '*' and our own '@'. No order is assumed. */
2077
2078void
2079mmix_asm_output_labelref (stream, name)
2080 FILE *stream;
2081 const char *name;
2082{
91009d64 2083 int is_extern = 1;
68cbb7e3 2084
2085 for (; (*name == '@' || *name == '*'); name++)
2086 if (*name == '@')
91009d64 2087 is_extern = 0;
68cbb7e3 2088
2089 asm_fprintf (stream, "%s%U%s",
2090 is_extern && TARGET_TOPLEVEL_SYMBOLS ? ":" : "",
2091 name);
2092}
2093
2094/* ASM_OUTPUT_INTERNAL_LABEL. */
2095
2096void
2097mmix_asm_output_internal_label (stream, name, num)
2098 FILE * stream;
2099 const char * name;
2100 int num;
2101{
2102 fprintf (stream, "%s:%d\tIS @\n", name, num);
2103}
2104
2105/* ASM_OUTPUT_DEF. */
2106
2107void
2108mmix_asm_output_def (stream, name, value)
2109 FILE * stream;
2110 const char * name;
2111 const char * value;
2112{
2113 assemble_name (stream, name);
2114 fprintf (stream, "\tIS ");
2115 assemble_name (stream, value);
2116 fputc ('\n', stream);
2117}
2118
2119/* ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL. */
2120
2121void
2122mmix_asm_output_define_label_difference_symbol (stream, symbol, hi, lo)
2123 FILE *stream;
2124 const char *symbol;
2125 const char *hi;
2126 const char *lo;
2127{
2128 assemble_name (stream, symbol);
2129 fprintf (stream, "\tIS\t");
2130 assemble_name (stream, hi);
2131 fputc ('-', stream);
2132 assemble_name (stream, lo);
2133 fprintf (stream, "\n");
2134}
2135
2136/* PRINT_OPERAND. */
2137
2138void
2139mmix_print_operand (stream, x, code)
2140 FILE * stream;
2141 rtx x;
2142 int code;
2143{
2144 /* When we add support for different codes later, we can, when needed,
2145 drop through to the main handler with a modified operand. */
2146 rtx modified_x = x;
2147
2148 switch (code)
2149 {
2150 /* Unrelated codes are in alphabetic order. */
2151
91009d64 2152 case '+':
2153 /* For conditional branches, output "P" for a probable branch. */
2154 if (TARGET_BRANCH_PREDICT)
2155 {
2156 x = find_reg_note (current_output_insn, REG_BR_PROB, 0);
2157 if (x && INTVAL (XEXP (x, 0)) > REG_BR_PROB_BASE / 2)
2158 putc ('P', stream);
2159 }
2160 return;
2161
68cbb7e3 2162 case 'B':
2163 if (GET_CODE (x) != CONST_INT)
2164 fatal_insn ("MMIX Internal: Expected a CONST_INT, not this", x);
2165 fprintf (stream, "%d", (int) (INTVAL (x) & 0xff));
2166 return;
2167
2168 case 'H':
2169 /* Highpart. Must be general register, and not the last one, as
2170 that one cannot be part of a consecutive register pair. */
2171 if (REGNO (x) > MMIX_LAST_GENERAL_REGISTER - 1)
2172 internal_error ("MMIX Internal: Bad register: %d", REGNO (x));
2173
2174 /* This is big-endian, so the high-part is the first one. */
2175 fprintf (stream, "%s", reg_names[REGNO (x)]);
2176 return;
2177
2178 case 'L':
2179 /* Lowpart. Must be CONST_INT or general register, and not the last
2180 one, as that one cannot be part of a consecutive register pair. */
2181 if (GET_CODE (x) == CONST_INT)
2182 {
2183 fprintf (stream, "#%lx",
2184 (unsigned long) (INTVAL (x)
2185 & ((unsigned int) 0x7fffffff * 2 + 1)));
2186 return;
2187 }
2188
2189 if (GET_CODE (x) == SYMBOL_REF)
2190 {
2191 output_addr_const (stream, x);
2192 return;
2193 }
2194
2195 if (REGNO (x) > MMIX_LAST_GENERAL_REGISTER - 1)
2196 internal_error ("MMIX Internal: Bad register: %d", REGNO (x));
2197
2198 /* This is big-endian, so the low-part is + 1. */
2199 fprintf (stream, "%s", reg_names[REGNO (x) + 1]);
2200 return;
2201
2202 /* Can't use 'a' because that's a generic modifier for address
2203 output. */
2204 case 'A':
2205 mmix_output_shiftvalue_op_from_str (stream, "ANDN",
2206 ~(unsigned HOST_WIDEST_INT)
2207 mmix_intval (x));
2208 return;
2209
2210 case 'i':
2211 mmix_output_shiftvalue_op_from_str (stream, "INC",
2212 (unsigned HOST_WIDEST_INT)
2213 mmix_intval (x));
2214 return;
2215
2216 case 'o':
2217 mmix_output_shiftvalue_op_from_str (stream, "OR",
2218 (unsigned HOST_WIDEST_INT)
2219 mmix_intval (x));
2220 return;
2221
2222 case 's':
2223 mmix_output_shiftvalue_op_from_str (stream, "SET",
2224 (unsigned HOST_WIDEST_INT)
2225 mmix_intval (x));
2226 return;
2227
2228 case 'd':
2229 case 'D':
2230 mmix_output_condition (stream, x, (code == 'D'));
2231 return;
2232
2233 case 'e':
2234 /* Output an extra "e" to make fcmpe, fune. */
2235 if (TARGET_FCMP_EPSILON)
2236 fprintf (stream, "e");
2237 return;
2238
2239 case 'm':
2240 /* Output the number minus 1. */
2241 if (GET_CODE (x) != CONST_INT)
2242 {
2243 fatal_insn ("MMIX Internal: Bad value for 'm', not a CONST_INT",
2244 x);
2245 }
2246 fprintf (stream, HOST_WIDEST_INT_PRINT_DEC,
2247 (HOST_WIDEST_INT) (mmix_intval (x) - 1));
2248 return;
2249
2250 case 'p':
2251 /* Store the number of registers we want to save. This was setup
2252 by the prologue. The actual operand contains the number of
2253 registers to pass, but we don't use it currently. Anyway, we
2254 need to output the number of saved registers here. */
2255 if (TARGET_ABI_GNU)
2256 fprintf (stream, "%d", mmix_highest_saved_stack_register + 1);
2257 else
2258 /* FIXME: Get the effect of renaming $16, $17.. to the first
2259 unused call-saved reg. */
2260 fprintf (stream, "15");
2261 return;
2262
2263 case 'r':
2264 /* Store the register to output a constant to. */
2265 if (! REG_P (x))
68435912 2266 fatal_insn ("MMIX Internal: Expected a register, not this", x);
68cbb7e3 2267 mmix_output_destination_register = REGNO (x);
2268 return;
2269
2270 case 'I':
2271 /* Output the constant. Note that we use this for floats as well. */
2272 if (GET_CODE (x) != CONST_INT
2273 && (GET_CODE (x) != CONST_DOUBLE
2274 || (GET_MODE (x) != VOIDmode && GET_MODE (x) != DFmode
2275 && GET_MODE (x) != SFmode)))
68435912 2276 fatal_insn ("MMIX Internal: Expected a constant, not this", x);
68cbb7e3 2277 mmix_output_register_setting (stream,
2278 mmix_output_destination_register,
2279 mmix_intval (x), 0);
2280 return;
2281
2282 case 'U':
2283 /* An U for unsigned, if TARGET_ZERO_EXTEND. Ignore the operand. */
2284 if (TARGET_ZERO_EXTEND)
2285 putc ('U', stream);
2286 return;
2287
2288 case 'v':
2289 mmix_output_shifted_value (stream, (HOST_WIDEST_INT) mmix_intval (x));
2290 return;
2291
2292 case 'V':
2293 mmix_output_shifted_value (stream, (HOST_WIDEST_INT) ~mmix_intval (x));
2294 return;
2295
2296 case 'W':
2297 if (GET_CODE (x) != CONST_INT)
2298 fatal_insn ("MMIX Internal: Expected a CONST_INT, not this", x);
2299 fprintf (stream, "#%x", (int) (INTVAL (x) & 0xffff));
2300 return;
2301
2302 case 0:
2303 /* Nothing to do. */
2304 break;
2305
2306 default:
2307 /* Presumably there's a missing case above if we get here. */
2308 internal_error ("MMIX Internal: Missing `%c' case in mmix_print_operand", code);
2309 }
2310
2311 switch (GET_CODE (modified_x))
2312 {
2313 case REG:
2314 if (REGNO (modified_x) >= FIRST_PSEUDO_REGISTER)
2315 internal_error ("MMIX Internal: Bad register: %d", REGNO (modified_x));
2316 fprintf (stream, "%s", reg_names[REGNO (modified_x)]);
2317 return;
2318
2319 case MEM:
2320 output_address (XEXP (modified_x, 0));
2321 return;
2322
2323 case CONST_INT:
2324 /* For -2147483648, mmixal complains that the constant does not fit
2325 in 4 bytes, so let's output it as hex. Take care to handle hosts
2326 where HOST_WIDE_INT is longer than an int.
2327
2328 Print small constants +-255 using decimal. */
2329
2330 if (INTVAL (modified_x) > -256 && INTVAL (modified_x) < 256)
2331 fprintf (stream, "%d", (int) (INTVAL (modified_x)));
2332 else
2333 fprintf (stream, "#%x",
2334 (int) (INTVAL (modified_x)) & (unsigned int) ~0);
2335 return;
2336
2337 case CONST_DOUBLE:
2338 /* Do somewhat as CONST_INT. */
58356836 2339 mmix_output_octa (stream, mmix_intval (modified_x), 0);
68cbb7e3 2340 return;
2341
2342 case CONST:
2343 output_addr_const (stream, modified_x);
2344 return;
2345
2346 default:
2347 /* No need to test for all strange things. Let output_addr_const do
2348 it for us. */
2349 if (CONSTANT_P (modified_x)
2350 /* Strangely enough, this is not included in CONSTANT_P.
2351 FIXME: Ask/check about sanity here. */
2352 || GET_CODE (modified_x) == CODE_LABEL)
2353 {
2354 output_addr_const (stream, modified_x);
2355 return;
2356 }
2357
2358 /* We need the original here. */
2359 fatal_insn ("MMIX Internal: Cannot decode this operand", x);
2360 }
2361}
2362
2363/* PRINT_OPERAND_PUNCT_VALID_P. */
2364
2365int
2366mmix_print_operand_punct_valid_p (code)
2367 int code ATTRIBUTE_UNUSED;
2368{
91009d64 2369 /* A '+' is used for branch prediction, similar to other ports. */
2370 return code == '+';
68cbb7e3 2371}
2372
2373/* PRINT_OPERAND_ADDRESS. */
2374
2375void
2376mmix_print_operand_address (stream, x)
2377 FILE *stream;
2378 rtx x;
2379{
2380 if (REG_P (x))
2381 {
2382 /* I find the generated assembly code harder to read without
2383 the ",0". */
2384 fprintf (stream, "%s,0",reg_names[REGNO (x)]);
2385 return;
2386 }
2387 else if (GET_CODE (x) == PLUS)
2388 {
2389 rtx x1 = XEXP (x, 0);
2390 rtx x2 = XEXP (x, 1);
2391
2392 /* Try swap the order. FIXME: Do we need this? */
2393 if (! REG_P (x1))
2394 {
2395 rtx tem = x1;
2396 x1 = x2;
2397 x2 = tem;
2398 }
2399
2400 if (REG_P (x1))
2401 {
2402 fprintf (stream, "%s,", reg_names[REGNO (x1)]);
2403
2404 if (REG_P (x2))
2405 {
2406 fprintf (stream, "%s", reg_names[REGNO (x2)]);
2407 return;
2408 }
2409 else if (GET_CODE (x2) == CONST_INT
2410 && CONST_OK_FOR_LETTER_P (INTVAL (x2), 'I'))
2411 {
2412 output_addr_const (stream, x2);
2413 return;
2414 }
2415 }
2416 }
2417
f0b228a5 2418 if (TARGET_BASE_ADDRESSES && mmix_legitimate_constant_p (x))
2419 {
2420 output_addr_const (stream, x);
2421 return;
2422 }
2423
68cbb7e3 2424 fatal_insn ("MMIX Internal: This is not a recognized address", x);
2425}
2426
2427/* ASM_OUTPUT_REG_PUSH. */
2428
2429void
2430mmix_asm_output_reg_push (stream, regno)
2431 FILE * stream;
2432 int regno;
2433{
2434 fprintf (stream, "\tSUBU %s,%s,8\n\tSTOU %s,%s,0\n",
2435 reg_names[MMIX_STACK_POINTER_REGNUM],
2436 reg_names[MMIX_STACK_POINTER_REGNUM],
2437 reg_names[regno],
2438 reg_names[MMIX_STACK_POINTER_REGNUM]);
2439}
2440
2441/* ASM_OUTPUT_REG_POP. */
2442
2443void
2444mmix_asm_output_reg_pop (stream, regno)
2445 FILE * stream;
2446 int regno;
2447{
2448 fprintf (stream, "\tLDOU %s,%s,0\n\tINCL %s,8\n",
2449 reg_names[regno],
2450 reg_names[MMIX_STACK_POINTER_REGNUM],
2451 reg_names[MMIX_STACK_POINTER_REGNUM]);
2452}
2453
2454/* ASM_OUTPUT_ADDR_DIFF_ELT. */
2455
2456void
2457mmix_asm_output_addr_diff_elt (stream, body, value, rel)
2458 FILE *stream;
2459 rtx body ATTRIBUTE_UNUSED;
2460 int value;
2461 int rel;
2462{
2463 fprintf (stream, "\tTETRA L%d-L%d\n", value, rel);
2464}
2465
2466/* ASM_OUTPUT_ADDR_VEC_ELT. */
2467
2468void
2469mmix_asm_output_addr_vec_elt (stream, value)
2470 FILE *stream;
2471 int value;
2472{
2473 fprintf (stream, "\tOCTA L:%d\n", value);
2474}
2475
2476/* ASM_OUTPUT_SKIP. */
2477
2478void
2479mmix_asm_output_skip (stream, nbytes)
2480 FILE *stream;
2481 int nbytes;
2482{
2483 fprintf (stream, "\tLOC @+%d\n", nbytes);
2484}
2485
2486/* ASM_OUTPUT_ALIGN. */
2487
2488void
2489mmix_asm_output_align (stream, power)
2490 FILE *stream;
2491 int power;
2492{
2493 /* We need to record the needed alignment of this section in the object,
2494 so we have to output an alignment directive. Use a .p2align (not
2495 .align) so people will never have to wonder about whether the
2496 argument is in number of bytes or the log2 thereof. We do it in
2497 addition to the LOC directive, so nothing needs tweaking when
2498 copy-pasting assembly into mmixal. */
2499 fprintf (stream, "\t.p2align %d\n", power);
2500 fprintf (stream, "\tLOC @+(%d-@)&%d\n", 1 << power, (1 << power) - 1);
2501}
2502
2503/* DBX_REGISTER_NUMBER. */
2504
2505int
2506mmix_dbx_register_number (regno)
2507 int regno;
2508{
2509 /* FIXME: Implement final register renumbering if necessary. (Use
2510 target state in cfun). */
2511
2512 /* We need to renumber registers to get the number of the return address
2513 register in the range 0..255. It is also space-saving if registers
2514 mentioned in the call-frame information (which uses this function by
2515 defaulting DWARF_FRAME_REGNUM to DBX_REGISTER_NUMBER) are numbered
2516 0 .. 63. So map 224 .. 256+15 -> 0 .. 47 and 0 .. 223 -> 48..223+48. */
2517 return regno >= 224 ? (regno - 224) : (regno + 48);
2518}
2519
35a3065a 2520/* End of target macro support functions.
68cbb7e3 2521
2522 Now MMIX's own functions. First the exported ones. */
2523
2524/* Output an optimal sequence for setting a register to a specific
2525 constant. Used in an alternative for const_ints in movdi, and when
2526 using large stack-frame offsets.
2527
2528 Use do_begin_end to say if a line-starting TAB and newline before the
2529 first insn and after the last insn is wanted. */
2530
2531void
2532mmix_output_register_setting (stream, regno, value, do_begin_end)
2533 FILE *stream;
2534 int regno;
2535 HOST_WIDEST_INT value;
2536 int do_begin_end;
2537{
2538 if (do_begin_end)
2539 fprintf (stream, "\t");
2540
2541 if (mmix_shiftable_wyde_value ((unsigned HOST_WIDEST_INT) value))
2542 {
2543 /* First, the one-insn cases. */
2544 mmix_output_shiftvalue_op_from_str (stream, "SET",
2545 (unsigned HOST_WIDEST_INT)
2546 value);
2547 fprintf (stream, " %s,", reg_names[regno]);
2548 mmix_output_shifted_value (stream, (unsigned HOST_WIDEST_INT) value);
2549 }
2550 else if (mmix_shiftable_wyde_value (-(unsigned HOST_WIDEST_INT) value))
2551 {
2552 /* We do this to get a bit more legible assembly code. The next
2553 alternative is mostly redundant with this. */
2554
2555 mmix_output_shiftvalue_op_from_str (stream, "SET",
2556 -(unsigned HOST_WIDEST_INT)
2557 value);
2558 fprintf (stream, " %s,", reg_names[regno]);
2559 mmix_output_shifted_value (stream, -(unsigned HOST_WIDEST_INT) value);
2560 fprintf (stream, "\n\tNEGU %s,0,%s", reg_names[regno],
2561 reg_names[regno]);
2562 }
2563 else if (mmix_shiftable_wyde_value (~(unsigned HOST_WIDEST_INT) value))
2564 {
2565 /* Slightly more expensive, the two-insn cases. */
2566
2567 /* FIXME: We could of course also test if 0..255-N or ~(N | 1..255)
2568 is shiftable, or any other one-insn transformation of the value.
2569 FIXME: Check first if the value is "shiftable" by two loading
2570 with two insns, since it makes more readable assembly code (if
2571 anyone else cares). */
2572
2573 mmix_output_shiftvalue_op_from_str (stream, "SET",
2574 ~(unsigned HOST_WIDEST_INT)
2575 value);
2576 fprintf (stream, " %s,", reg_names[regno]);
2577 mmix_output_shifted_value (stream, ~(unsigned HOST_WIDEST_INT) value);
2578 fprintf (stream, "\n\tNOR %s,%s,0", reg_names[regno],
2579 reg_names[regno]);
2580 }
2581 else
2582 {
2583 /* The generic case. 2..4 insns. */
25037517 2584 static const char *const higher_parts[] = {"L", "ML", "MH", "H"};
68cbb7e3 2585 const char *op = "SET";
2586 const char *line_begin = "";
f0b228a5 2587 int insns = 0;
68cbb7e3 2588 int i;
f0b228a5 2589 HOST_WIDEST_INT tmpvalue = value;
68cbb7e3 2590
f0b228a5 2591 /* Compute the number of insns needed to output this constant. */
2592 for (i = 0; i < 4 && tmpvalue != 0; i++)
2593 {
2594 if (tmpvalue & 65535)
2595 insns++;
2596 tmpvalue >>= 16;
2597 }
2598 if (TARGET_BASE_ADDRESSES && insns == 3)
2599 {
2600 /* The number three is based on a static observation on
2601 ghostscript-6.52. Two and four are excluded because there
2602 are too many such constants, and each unique constant (maybe
2603 offset by 1..255) were used few times compared to other uses,
2604 e.g. addresses.
2605
2606 We use base-plus-offset addressing to force it into a global
2607 register; we just use a "LDA reg,VALUE", which will cause the
2608 assembler and linker to DTRT (for constants as well as
2609 addresses). */
2610 fprintf (stream, "LDA %s,", reg_names[regno]);
2611 mmix_output_octa (stream, value, 0);
2612 }
2613 else
68cbb7e3 2614 {
f0b228a5 2615 /* Output pertinent parts of the 4-wyde sequence.
2616 Still more to do if we want this to be optimal, but hey...
2617 Note that the zero case has been handled above. */
2618 for (i = 0; i < 4 && value != 0; i++)
68cbb7e3 2619 {
f0b228a5 2620 if (value & 65535)
2621 {
2622 fprintf (stream, "%s%s%s %s,#%x", line_begin, op,
2623 higher_parts[i], reg_names[regno],
2624 (int) (value & 65535));
2625 /* The first one sets the rest of the bits to 0, the next
2626 ones add set bits. */
2627 op = "INC";
2628 line_begin = "\n\t";
2629 }
68cbb7e3 2630
f0b228a5 2631 value >>= 16;
2632 }
68cbb7e3 2633 }
2634 }
2635
2636 if (do_begin_end)
2637 fprintf (stream, "\n");
2638}
2639
2640/* Return 1 if value is 0..65535*2**(16*N) for N=0..3.
2641 else return 0. */
2642
2643int
2644mmix_shiftable_wyde_value (value)
2645 unsigned HOST_WIDEST_INT value;
2646{
2647 /* Shift by 16 bits per group, stop when we've found two groups with
2648 nonzero bits. */
2649 int i;
2650 int has_candidate = 0;
2651
2652 for (i = 0; i < 4; i++)
2653 {
2654 if (value & 65535)
2655 {
2656 if (has_candidate)
2657 return 0;
2658 else
2659 has_candidate = 1;
2660 }
2661
2662 value >>= 16;
2663 }
2664
2665 return 1;
2666}
2667
2668/* True if this is an address_operand or a symbolic operand. */
2669
2670int
2671mmix_symbolic_or_address_operand (op, mode)
2672 rtx op;
2673 enum machine_mode mode;
2674{
2675 switch (GET_CODE (op))
2676 {
2677 case SYMBOL_REF:
2678 case LABEL_REF:
2679 return 1;
2680 case CONST:
2681 op = XEXP (op, 0);
2682 if ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
2683 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
2684 && (GET_CODE (XEXP (op, 1)) == CONST_INT
2685 || (GET_CODE (XEXP (op, 1)) == CONST_DOUBLE
2686 && GET_MODE (XEXP (op, 1)) == VOIDmode)))
2687 return 1;
2688 /* FALLTHROUGH */
2689 default:
2690 return address_operand (op, mode);
2691 }
2692}
2693
2694/* True if this is a register or CONST_INT (or CONST_DOUBLE for DImode).
2695 We could narrow the value down with a couple of predicated, but that
2696 doesn't seem to be worth it at the moment. */
2697
2698int
2699mmix_reg_or_constant_operand (op, mode)
2700 rtx op;
2701 enum machine_mode mode;
2702{
2703 return register_operand (op, mode)
2704 || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)
2705 || GET_CODE (op) == CONST_INT;
2706}
2707
2708/* True if this is a register with a condition-code mode. */
2709
2710int
2711mmix_reg_cc_operand (op, mode)
2712 rtx op;
2713 enum machine_mode mode;
2714{
2715 if (mode == VOIDmode)
2716 mode = GET_MODE (op);
2717
2718 return register_operand (op, mode)
2719 && (mode == CCmode || mode == CC_UNSmode || mode == CC_FPmode
2720 || mode == CC_FPEQmode || mode == CC_FUNmode);
2721}
2722
2723/* True if this is a foldable comparison operator
2724 - one where a the result of (compare:CC (reg) (const_int 0)) can be
2725 replaced by (reg). */
2726
2727int
2728mmix_foldable_comparison_operator (op, mode)
2729 rtx op;
2730 enum machine_mode mode;
2731{
2732 RTX_CODE code = GET_CODE (op);
2733
2734 if (mode == VOIDmode)
2735 mode = GET_MODE (op);
2736
2737 if (mode == VOIDmode && GET_RTX_CLASS (GET_CODE (op)) == '<')
2738 mode = GET_MODE (XEXP (op, 0));
2739
2740 return ((mode == CCmode || mode == DImode)
2741 && (code == NE || code == EQ || code == GE || code == GT
2742 || code == LE))
2743 /* FIXME: This may be a stupid trick. What happens when GCC wants to
2744 reverse the condition? Can it do that by itself? Maybe it can
2745 even reverse the condition to fit a foldable one in the first
2746 place? */
2747 || (mode == CC_UNSmode && (code == GTU || code == LEU));
2748}
2749
2750/* Like comparison_operator, but only true if this comparison operator is
2751 applied to a valid mode. Needed to avoid jump.c generating invalid
2752 code with -ffast-math (gcc.dg/20001228-1.c). */
2753
2754int
2755mmix_comparison_operator (op, mode)
2756 rtx op;
2757 enum machine_mode mode;
2758{
2759 RTX_CODE code = GET_CODE (op);
2760
2761 /* Comparison operators usually don't have a mode, but let's try and get
2762 one anyway for the day that changes. */
2763 if (mode == VOIDmode)
2764 mode = GET_MODE (op);
2765
2766 /* Get the mode from the first operand if we don't have one. */
2767 if (mode == VOIDmode && GET_RTX_CLASS (GET_CODE (op)) == '<')
2768 mode = GET_MODE (XEXP (op, 0));
2769
2770 /* FIXME: This needs to be kept in sync with the tables in
2771 mmix_output_condition. */
2772 return
2773 (mode == VOIDmode && GET_RTX_CLASS (GET_CODE (op)) == '<')
2774 || (mode == CC_FUNmode
2775 && (code == ORDERED || code == UNORDERED))
2776 || (mode == CC_FPmode
2777 && (code == GT || code == LT))
2778 || (mode == CC_FPEQmode
2779 && (code == NE || code == EQ))
2780 || (mode == CC_UNSmode
2781 && (code == GEU || code == GTU || code == LEU || code == LTU))
2782 || (mode == CCmode
2783 && (code == NE || code == EQ || code == GE || code == GT
2784 || code == LE || code == LT))
2785 || (mode == DImode
2786 && (code == NE || code == EQ || code == GE || code == GT
2787 || code == LE || code == LT || code == LEU || code == GTU));
2788}
2789
2790/* True if this is a register or 0 (int or float). */
2791
2792int
2793mmix_reg_or_0_operand (op, mode)
2794 rtx op;
2795 enum machine_mode mode;
2796{
2797 /* FIXME: Is mode calculation necessary and correct? */
2798 return
2799 op == CONST0_RTX (mode == VOIDmode ? GET_MODE (op) : mode)
2800 || register_operand (op, mode);
2801}
2802
2803/* True if this is a register or an int 0..255. */
2804
2805int
2806mmix_reg_or_8bit_operand (op, mode)
2807 rtx op;
2808 enum machine_mode mode;
2809{
2810 return register_operand (op, mode)
2811 || (GET_CODE (op) == CONST_INT
2812 && CONST_OK_FOR_LETTER_P (INTVAL (op), 'I'));
2813}
2814
2815/* True if this is a register or an int 0..256. We include 256,
2816 because it can be canonicalized into 255 for comparisons, which is
2817 currently the only use of this predicate.
2818 FIXME: Check that this happens and does TRT. */
2819
2820int
2821mmix_reg_or_8bit_or_256_operand (op, mode)
2822 rtx op;
2823 enum machine_mode mode;
2824{
2825 return mmix_reg_or_8bit_operand (op, mode)
2826 || (GET_CODE (op) == CONST_INT && INTVAL (op) == 256);
2827}
2828
2829/* Returns zero if code and mode is not a valid condition from a
2830 compare-type insn. Nonzero if it is. The parameter op, if non-NULL,
2831 is the comparison of mode is CC-somethingmode. */
2832
2833int
2834mmix_valid_comparison (code, mode, op)
2835 RTX_CODE code;
2836 enum machine_mode mode;
2837 rtx op;
2838{
2839 if (mode == VOIDmode && op != NULL_RTX)
2840 mode = GET_MODE (op);
2841
2842 /* We don't care to look at these, they should always be valid. */
2843 if (mode == CCmode || mode == CC_UNSmode || mode == DImode)
2844 return 1;
2845
2846 if ((mode == CC_FPmode || mode == DFmode)
2847 && (code == GT || code == LT))
2848 return 1;
2849
2850 if ((mode == CC_FPEQmode || mode == DFmode)
2851 && (code == EQ || code == NE))
2852 return 1;
2853
2854 if ((mode == CC_FUNmode || mode == DFmode)
2855 && (code == ORDERED || code == UNORDERED))
2856 return 1;
2857
2858 return 0;
2859}
2860
2861/* X and Y are two things to compare using CODE. Emit a compare insn if
2862 possible and return the rtx for the cc-reg in the proper mode, or
2863 NULL_RTX if this is not a valid comparison. */
2864
2865rtx
2866mmix_gen_compare_reg (code, x, y)
2867 RTX_CODE code;
2868 rtx x, y;
2869{
2870 enum machine_mode ccmode = SELECT_CC_MODE (code, x, y);
2871 rtx cc_reg;
2872
2873 /* FIXME: Do we get constants here? Of double mode? */
2874 enum machine_mode mode
2875 = GET_MODE (x) == VOIDmode
2876 ? GET_MODE (y)
2877 : GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT ? DFmode : DImode;
2878
2879 if (! mmix_valid_comparison (code, mode, x))
2880 return NULL_RTX;
2881
2882 cc_reg = gen_reg_rtx (ccmode);
2883
2884 /* FIXME: Can we avoid emitting a compare insn here? */
2885 if (! REG_P (x) && ! REG_P (y))
2886 x = force_reg (mode, x);
2887
2888 CANONICALIZE_COMPARISON (code, x, y);
2889
2890 /* If it's not quite right yet, put y in a register. */
2891 if (! REG_P (y)
2892 && (GET_CODE (y) != CONST_INT
2893 || ! CONST_OK_FOR_LETTER_P (INTVAL (y), 'I')))
2894 y = force_reg (mode, y);
2895
2896 emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
2897 gen_rtx_COMPARE (ccmode, x, y)));
2898
2899 return cc_reg;
2900}
2901
2902/* Local (static) helper functions. */
2903
2904/* Print operator suitable for doing something with a shiftable
ebb11c7b 2905 wyde. The type of operator is passed as an asm output modifier. */
68cbb7e3 2906
2907static void
2908mmix_output_shiftvalue_op_from_str (stream, mainop, value)
2909 FILE *stream;
2910 const char *mainop;
2911 HOST_WIDEST_INT value;
2912{
25037517 2913 static const char *const op_part[] = {"L", "ML", "MH", "H"};
68cbb7e3 2914 int i;
2915
2916 if (! mmix_shiftable_wyde_value (value))
2917 {
2918 char s[sizeof ("0xffffffffffffffff")];
2919 sprintf (s, HOST_WIDEST_INT_PRINT_HEX, value);
2920 internal_error ("MMIX Internal: %s is not a shiftable int", s);
2921 }
2922
2923 for (i = 0; i < 4; i++)
2924 {
2925 /* We know we're through when we find one-bits in the low
2926 16 bits. */
2927 if (value & 0xffff)
2928 {
2929 fprintf (stream, "%s%s", mainop, op_part[i]);
2930 return;
2931 }
2932 value >>= 16;
2933 }
2934
2935 /* No bits set? Then it must have been zero. */
2936 fprintf (stream, "%sL", mainop);
2937}
2938
2939/* Print a 64-bit value, optionally prefixed by assembly pseudo. */
2940
2941static void
2942mmix_output_octa (stream, value, do_begin_end)
2943 FILE *stream;
2944 HOST_WIDEST_INT value;
2945 int do_begin_end;
2946{
2947 /* Snipped from final.c:output_addr_const. We need to avoid the
2948 presumed universal "0x" prefix. We can do it by replacing "0x" with
2949 "#0" here; we must avoid a space in the operands and no, the zero
2950 won't cause the number to be assumed in octal format. */
2951 char hex_format[sizeof (HOST_WIDEST_INT_PRINT_HEX)];
2952
2953 if (do_begin_end)
2954 fprintf (stream, "\tOCTA ");
2955
2956 strcpy (hex_format, HOST_WIDEST_INT_PRINT_HEX);
2957 hex_format[0] = '#';
2958 hex_format[1] = '0';
2959
2960 /* Provide a few alternative output formats depending on the number, to
2961 improve legibility of assembler output. */
2962 if ((value < (HOST_WIDEST_INT) 0 && value > (HOST_WIDEST_INT) -10000)
2963 || (value >= (HOST_WIDEST_INT) 0 && value <= (HOST_WIDEST_INT) 16384))
2964 fprintf (stream, "%d", (int) value);
2965 else if (value > (HOST_WIDEST_INT) 0
2966 && value < ((HOST_WIDEST_INT) 1 << 31) * 2)
2967 fprintf (stream, "#%x", (unsigned int) value);
2968 else
2969 fprintf (stream, hex_format, value);
2970
2971 if (do_begin_end)
2972 fprintf (stream, "\n");
2973}
2974
2975/* Print the presumed shiftable wyde argument shifted into place (to
2976 be output with an operand). */
2977
2978static void
2979mmix_output_shifted_value (stream, value)
2980 FILE * stream;
2981 HOST_WIDEST_INT value;
2982{
2983 int i;
2984
2985 if (! mmix_shiftable_wyde_value (value))
2986 {
2987 char s[16+2+1];
2988 sprintf (s, HOST_WIDEST_INT_PRINT_HEX, value);
2989 internal_error ("MMIX Internal: %s is not a shiftable int", s);
2990 }
2991
2992 for (i = 0; i < 4; i++)
2993 {
2994 /* We know we're through when we find one-bits in the low 16 bits. */
2995 if (value & 0xffff)
2996 {
2997 fprintf (stream, "#%x", (int) (value & 0xffff));
2998 return;
2999 }
3000
3001 value >>= 16;
3002 }
3003
3004 /* No bits set? Then it must have been zero. */
3005 fprintf (stream, "0");
3006}
3007
3008/* Output an MMIX condition name corresponding to an operator
3009 and operands:
3010 (comparison_operator [(comparison_operator ...) (const_int 0)])
3011 which means we have to look at *two* operators.
3012
3013 The argument "reversed" refers to reversal of the condition (not the
3014 same as swapping the arguments). */
3015
3016static void
3017mmix_output_condition (stream, x, reversed)
3018 FILE *stream;
3019 rtx x;
3020 int reversed;
3021{
3022 struct cc_conv
3023 {
3024 RTX_CODE cc;
3025
3026 /* The normal output cc-code. */
3027 const char *const normal;
3028
3029 /* The reversed cc-code, or NULL if invalid. */
3030 const char *const reversed;
3031 };
3032
3033 struct cc_type_conv
3034 {
3035 enum machine_mode cc_mode;
3036
3037 /* Terminated with {NIL, NULL, NULL} */
3038 const struct cc_conv *const convs;
3039 };
3040
3041#undef CCEND
3042#define CCEND {NIL, NULL, NULL}
3043
3044 static const struct cc_conv cc_fun_convs[]
3045 = {{ORDERED, "Z", "P"},
3046 {UNORDERED, "P", "Z"},
3047 CCEND};
3048 static const struct cc_conv cc_fp_convs[]
3049 = {{GT, "P", NULL},
3050 {LT, "N", NULL},
3051 CCEND};
3052 static const struct cc_conv cc_fpeq_convs[]
3053 = {{NE, "Z", "P"},
3054 {EQ, "P", "Z"},
3055 CCEND};
3056 static const struct cc_conv cc_uns_convs[]
3057 = {{GEU, "NN", "N"},
3058 {GTU, "P", "NP"},
3059 {LEU, "NP", "P"},
3060 {LTU, "N", "NN"},
3061 CCEND};
3062 static const struct cc_conv cc_signed_convs[]
3063 = {{NE, "NZ", "Z"},
3064 {EQ, "Z", "NZ"},
3065 {GE, "NN", "N"},
3066 {GT, "P", "NP"},
3067 {LE, "NP", "P"},
3068 {LT, "N", "NN"},
3069 CCEND};
3070 static const struct cc_conv cc_di_convs[]
3071 = {{NE, "NZ", "Z"},
3072 {EQ, "Z", "NZ"},
3073 {GE, "NN", "N"},
3074 {GT, "P", "NP"},
3075 {LE, "NP", "P"},
3076 {LT, "N", "NN"},
3077 {GTU, "NZ", "Z"},
3078 {LEU, "Z", "NZ"},
3079 CCEND};
3080#undef CCEND
3081
3082 static const struct cc_type_conv cc_convs[]
3083 = {{CC_FUNmode, cc_fun_convs},
3084 {CC_FPmode, cc_fp_convs},
3085 {CC_FPEQmode, cc_fpeq_convs},
3086 {CC_UNSmode, cc_uns_convs},
3087 {CCmode, cc_signed_convs},
3088 {DImode, cc_di_convs}};
3089
3090 unsigned int i;
3091 int j;
3092
3093 enum machine_mode mode = GET_MODE (XEXP (x, 0));
3094 RTX_CODE cc = GET_CODE (x);
3095
3096 for (i = 0; i < sizeof (cc_convs)/sizeof(*cc_convs); i++)
3097 {
3098 if (mode == cc_convs[i].cc_mode)
3099 {
3100 for (j = 0; cc_convs[i].convs[j].cc != NIL; j++)
3101 if (cc == cc_convs[i].convs[j].cc)
3102 {
3103 const char *mmix_cc
3104 = (reversed ? cc_convs[i].convs[j].reversed
3105 : cc_convs[i].convs[j].normal);
3106
3107 if (mmix_cc == NULL)
3108 fatal_insn ("MMIX Internal: Trying to output invalidly\
3109 reversed condition:", x);
3110
3111 fprintf (stream, "%s", mmix_cc);
3112 return;
3113 }
3114
3115 fatal_insn ("MMIX Internal: What's the CC of this?", x);
3116 }
3117 }
3118
3119 fatal_insn ("MMIX Internal: What is the CC of this?", x);
3120}
3121
3122/* Return the bit-value for a const_int or const_double. */
3123
3124static HOST_WIDEST_INT
3125mmix_intval (x)
3126 rtx x;
3127{
3128 unsigned HOST_WIDEST_INT retval;
3129
3130 if (GET_CODE (x) == CONST_INT)
3131 return INTVAL (x);
3132
3133 /* We make a little song and dance because converting to long long in
3134 gcc-2.7.2 is broken. I still want people to be able to use it for
3135 cross-compilation to MMIX. */
3136 if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == VOIDmode)
3137 {
3138 if (sizeof (HOST_WIDE_INT) < sizeof (HOST_WIDEST_INT))
3139 {
3140 retval = (unsigned) CONST_DOUBLE_LOW (x) / 2;
3141 retval *= 2;
3142 retval |= CONST_DOUBLE_LOW (x) & 1;
3143
3144 retval |=
3145 (unsigned HOST_WIDEST_INT) CONST_DOUBLE_HIGH (x)
3146 << (HOST_BITS_PER_LONG);
3147 }
3148 else
3149 retval = CONST_DOUBLE_HIGH (x);
3150
3151 return retval;
3152 }
3153
3154 if (GET_CODE (x) == CONST_DOUBLE)
3155 {
3156 REAL_VALUE_TYPE value;
3157
3158 /* FIXME: This macro is not in the manual but should be. */
3159 REAL_VALUE_FROM_CONST_DOUBLE (value, x);
3160
3161 if (GET_MODE (x) == DFmode)
3162 {
3163 long bits[2];
dc8dc4ce 3164
68cbb7e3 3165 REAL_VALUE_TO_TARGET_DOUBLE (value, bits);
3166
3167 if (sizeof (long) < sizeof (HOST_WIDEST_INT))
3168 {
3169 retval = (unsigned long) bits[1] / 2;
3170 retval *= 2;
3171 retval |= (unsigned long) bits[1] & 1;
3172 retval
3173 |= (unsigned HOST_WIDEST_INT) bits[0]
3174 << (sizeof (bits[0]) * 8);
3175 }
3176 else
3177 retval = (unsigned long) bits[1];
3178
3179 return retval;
3180 }
3181 else if (GET_MODE (x) == SFmode)
3182 {
3183 long bits;
3184 REAL_VALUE_TO_TARGET_SINGLE (value, bits);
3185
3186 return (unsigned long) bits;
3187 }
3188 }
3189
3190 fatal_insn ("MMIX Internal: This is not a constant:", x);
3191}
3192
3193/*
3194 * Local variables:
3195 * eval: (c-set-style "gnu")
3196 * indent-tabs-mode: t
3197 * End:
3198 */