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