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