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