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