]> gcc.gnu.org Git - gcc.git/blame - gcc/config/mep/mep.c
Daily bump.
[gcc.git] / gcc / config / mep / mep.c
CommitLineData
7acf4da6
DD
1/* Definitions for Toshiba Media Processor
2 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
3 Free Software Foundation, Inc.
4 Contributed by Red Hat, Inc.
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 3, or (at your option) any later
11version.
12
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
19along with GCC; see the file COPYING3. If not see
20<http://www.gnu.org/licenses/>. */
21
22#include "config.h"
23#include "system.h"
24#include "coretypes.h"
25#include "tm.h"
26#include "rtl.h"
27#include "tree.h"
28#include "regs.h"
29#include "hard-reg-set.h"
30#include "real.h"
31#include "insn-config.h"
32#include "conditions.h"
33#include "insn-flags.h"
34#include "output.h"
35#include "insn-attr.h"
36#include "flags.h"
37#include "recog.h"
38#include "obstack.h"
39#include "tree.h"
40#include "expr.h"
41#include "except.h"
42#include "function.h"
43#include "optabs.h"
44#include "reload.h"
45#include "tm_p.h"
46#include "ggc.h"
47#include "toplev.h"
48#include "integrate.h"
49#include "target.h"
50#include "target-def.h"
51#include "langhooks.h"
52#include "df.h"
53
54/* Structure of this file:
55
56 + Command Line Option Support
57 + Pattern support - constraints, predicates, expanders
58 + Reload Support
59 + Costs
60 + Functions to save and restore machine-specific function data.
61 + Frame/Epilog/Prolog Related
62 + Operand Printing
63 + Function args in registers
64 + Handle pipeline hazards
65 + Handle attributes
66 + Trampolines
67 + Machine-dependent Reorg
68 + Builtins. */
69
70/* Symbol encodings:
71
72 Symbols are encoded as @ <char> . <name> where <char> is one of these:
73
74 b - based
75 t - tiny
76 n - near
77 f - far
78 i - io, near
79 I - io, far
80 c - cb (control bus) */
81
82struct GTY(()) machine_function
83{
84 int mep_frame_pointer_needed;
85
86 /* For varargs. */
87 int arg_regs_to_save;
88 int regsave_filler;
89 int frame_filler;
e756464b 90 int frame_locked;
7acf4da6
DD
91
92 /* Records __builtin_return address. */
93 rtx eh_stack_adjust;
94
95 int reg_save_size;
96 int reg_save_slot[FIRST_PSEUDO_REGISTER];
97 unsigned char reg_saved[FIRST_PSEUDO_REGISTER];
98
99 /* 2 if the current function has an interrupt attribute, 1 if not, 0
100 if unknown. This is here because resource.c uses EPILOGUE_USES
101 which needs it. */
102 int interrupt_handler;
103
104 /* Likewise, for disinterrupt attribute. */
105 int disable_interrupts;
106
107 /* Number of doloop tags used so far. */
108 int doloop_tags;
109
110 /* True if the last tag was allocated to a doloop_end. */
111 bool doloop_tag_from_end;
112
113 /* True if reload changes $TP. */
114 bool reload_changes_tp;
115
116 /* 2 if there are asm()s without operands, 1 if not, 0 if unknown.
117 We only set this if the function is an interrupt handler. */
118 int asms_without_operands;
119};
120
121#define MEP_CONTROL_REG(x) \
122 (GET_CODE (x) == REG && ANY_CONTROL_REGNO_P (REGNO (x)))
123
124static const struct attribute_spec mep_attribute_table[11];
125
126static GTY(()) section * based_section;
127static GTY(()) section * tinybss_section;
128static GTY(()) section * far_section;
129static GTY(()) section * farbss_section;
130static GTY(()) section * frodata_section;
131static GTY(()) section * srodata_section;
132
820ca276
DD
133static GTY(()) section * vtext_section;
134static GTY(()) section * vftext_section;
135static GTY(()) section * ftext_section;
136
7acf4da6
DD
137static void mep_set_leaf_registers (int);
138static bool symbol_p (rtx);
139static bool symbolref_p (rtx);
140static void encode_pattern_1 (rtx);
141static void encode_pattern (rtx);
142static bool const_in_range (rtx, int, int);
143static void mep_rewrite_mult (rtx, rtx);
144static void mep_rewrite_mulsi3 (rtx, rtx, rtx, rtx);
145static void mep_rewrite_maddsi3 (rtx, rtx, rtx, rtx, rtx);
146static bool mep_reuse_lo_p_1 (rtx, rtx, rtx, bool);
147static bool move_needs_splitting (rtx, rtx, enum machine_mode);
148static bool mep_expand_setcc_1 (enum rtx_code, rtx, rtx, rtx);
149static bool mep_nongeneral_reg (rtx);
150static bool mep_general_copro_reg (rtx);
151static bool mep_nonregister (rtx);
152static struct machine_function* mep_init_machine_status (void);
153static rtx mep_tp_rtx (void);
154static rtx mep_gp_rtx (void);
155static bool mep_interrupt_p (void);
156static bool mep_disinterrupt_p (void);
157static bool mep_reg_set_p (rtx, rtx);
158static bool mep_reg_set_in_function (int);
159static bool mep_interrupt_saved_reg (int);
160static bool mep_call_saves_register (int);
161static rtx F (rtx);
162static void add_constant (int, int, int, int);
163static bool mep_function_uses_sp (void);
164static rtx maybe_dead_move (rtx, rtx, bool);
165static void mep_reload_pointer (int, const char *);
166static void mep_start_function (FILE *, HOST_WIDE_INT);
167static bool mep_function_ok_for_sibcall (tree, tree);
168static int unique_bit_in (HOST_WIDE_INT);
169static int bit_size_for_clip (HOST_WIDE_INT);
170static int bytesize (const_tree, enum machine_mode);
171static tree mep_validate_based_tiny (tree *, tree, tree, int, bool *);
172static tree mep_validate_near_far (tree *, tree, tree, int, bool *);
173static tree mep_validate_disinterrupt (tree *, tree, tree, int, bool *);
174static tree mep_validate_interrupt (tree *, tree, tree, int, bool *);
175static tree mep_validate_io_cb (tree *, tree, tree, int, bool *);
176static tree mep_validate_vliw (tree *, tree, tree, int, bool *);
177static bool mep_function_attribute_inlinable_p (const_tree);
5cec9f59 178static bool mep_can_inline_p (tree, tree);
7acf4da6
DD
179static bool mep_lookup_pragma_disinterrupt (const char *);
180static int mep_multiple_address_regions (tree, bool);
181static int mep_attrlist_to_encoding (tree, tree);
182static void mep_insert_attributes (tree, tree *);
183static void mep_encode_section_info (tree, rtx, int);
184static section * mep_select_section (tree, int, unsigned HOST_WIDE_INT);
185static void mep_unique_section (tree, int);
186static unsigned int mep_section_type_flags (tree, const char *, int);
187static void mep_asm_named_section (const char *, unsigned int, tree);
188static bool mep_mentioned_p (rtx, rtx, int);
189static void mep_reorg_regmove (rtx);
190static rtx mep_insert_repeat_label_last (rtx, rtx, bool, bool);
191static void mep_reorg_repeat (rtx);
192static bool mep_invertable_branch_p (rtx);
193static void mep_invert_branch (rtx, rtx);
194static void mep_reorg_erepeat (rtx);
195static void mep_jmp_return_reorg (rtx);
196static void mep_reorg_addcombine (rtx);
197static void mep_reorg (void);
198static void mep_init_intrinsics (void);
199static void mep_init_builtins (void);
200static void mep_intrinsic_unavailable (int);
201static bool mep_get_intrinsic_insn (int, const struct cgen_insn **);
202static bool mep_get_move_insn (int, const struct cgen_insn **);
203static rtx mep_convert_arg (enum machine_mode, rtx);
204static rtx mep_convert_regnum (const struct cgen_regnum_operand *, rtx);
205static rtx mep_legitimize_arg (const struct insn_operand_data *, rtx, int);
206static void mep_incompatible_arg (const struct insn_operand_data *, rtx, int, tree);
207static rtx mep_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
208static int mep_adjust_cost (rtx, rtx, rtx, int);
209static int mep_issue_rate (void);
210static rtx mep_find_ready_insn (rtx *, int, enum attr_slot, int);
211static void mep_move_ready_insn (rtx *, int, rtx);
212static int mep_sched_reorder (FILE *, int, rtx *, int *, int);
213static rtx mep_make_bundle (rtx, rtx);
214static void mep_bundle_insns (rtx);
215static bool mep_rtx_cost (rtx, int, int, int *, bool);
216static int mep_address_cost (rtx, bool);
217static void mep_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
218 tree, int *, int);
219static bool mep_pass_by_reference (CUMULATIVE_ARGS * cum, enum machine_mode,
220 const_tree, bool);
221static bool mep_vector_mode_supported_p (enum machine_mode);
222static bool mep_handle_option (size_t, const char *, int);
223static rtx mep_allocate_initial_value (rtx);
224static void mep_asm_init_sections (void);
225static int mep_comp_type_attributes (const_tree, const_tree);
226static bool mep_narrow_volatile_bitfield (void);
227static rtx mep_expand_builtin_saveregs (void);
228static tree mep_build_builtin_va_list (void);
229static void mep_expand_va_start (tree, rtx);
230static tree mep_gimplify_va_arg_expr (tree, tree, tree *, tree *);
7b5cbb57 231static bool mep_can_eliminate (const int, const int);
7acf4da6
DD
232\f
233/* Initialize the GCC target structure. */
234
235#undef TARGET_ASM_FUNCTION_PROLOGUE
236#define TARGET_ASM_FUNCTION_PROLOGUE mep_start_function
237#undef TARGET_ATTRIBUTE_TABLE
238#define TARGET_ATTRIBUTE_TABLE mep_attribute_table
239#undef TARGET_COMP_TYPE_ATTRIBUTES
240#define TARGET_COMP_TYPE_ATTRIBUTES mep_comp_type_attributes
241#undef TARGET_INSERT_ATTRIBUTES
242#define TARGET_INSERT_ATTRIBUTES mep_insert_attributes
243#undef TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P
244#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P mep_function_attribute_inlinable_p
5cec9f59
DD
245#undef TARGET_CAN_INLINE_P
246#define TARGET_CAN_INLINE_P mep_can_inline_p
7acf4da6
DD
247#undef TARGET_SECTION_TYPE_FLAGS
248#define TARGET_SECTION_TYPE_FLAGS mep_section_type_flags
249#undef TARGET_ASM_NAMED_SECTION
250#define TARGET_ASM_NAMED_SECTION mep_asm_named_section
251#undef TARGET_INIT_BUILTINS
252#define TARGET_INIT_BUILTINS mep_init_builtins
253#undef TARGET_EXPAND_BUILTIN
254#define TARGET_EXPAND_BUILTIN mep_expand_builtin
255#undef TARGET_SCHED_ADJUST_COST
256#define TARGET_SCHED_ADJUST_COST mep_adjust_cost
257#undef TARGET_SCHED_ISSUE_RATE
258#define TARGET_SCHED_ISSUE_RATE mep_issue_rate
259#undef TARGET_SCHED_REORDER
260#define TARGET_SCHED_REORDER mep_sched_reorder
261#undef TARGET_STRIP_NAME_ENCODING
262#define TARGET_STRIP_NAME_ENCODING mep_strip_name_encoding
263#undef TARGET_ASM_SELECT_SECTION
264#define TARGET_ASM_SELECT_SECTION mep_select_section
265#undef TARGET_ASM_UNIQUE_SECTION
266#define TARGET_ASM_UNIQUE_SECTION mep_unique_section
267#undef TARGET_ENCODE_SECTION_INFO
268#define TARGET_ENCODE_SECTION_INFO mep_encode_section_info
269#undef TARGET_FUNCTION_OK_FOR_SIBCALL
270#define TARGET_FUNCTION_OK_FOR_SIBCALL mep_function_ok_for_sibcall
271#undef TARGET_RTX_COSTS
272#define TARGET_RTX_COSTS mep_rtx_cost
273#undef TARGET_ADDRESS_COST
274#define TARGET_ADDRESS_COST mep_address_cost
275#undef TARGET_MACHINE_DEPENDENT_REORG
276#define TARGET_MACHINE_DEPENDENT_REORG mep_reorg
277#undef TARGET_SETUP_INCOMING_VARARGS
278#define TARGET_SETUP_INCOMING_VARARGS mep_setup_incoming_varargs
279#undef TARGET_PASS_BY_REFERENCE
280#define TARGET_PASS_BY_REFERENCE mep_pass_by_reference
281#undef TARGET_VECTOR_MODE_SUPPORTED_P
282#define TARGET_VECTOR_MODE_SUPPORTED_P mep_vector_mode_supported_p
283#undef TARGET_HANDLE_OPTION
284#define TARGET_HANDLE_OPTION mep_handle_option
285#undef TARGET_DEFAULT_TARGET_FLAGS
286#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
287#undef TARGET_ALLOCATE_INITIAL_VALUE
288#define TARGET_ALLOCATE_INITIAL_VALUE mep_allocate_initial_value
289#undef TARGET_ASM_INIT_SECTIONS
290#define TARGET_ASM_INIT_SECTIONS mep_asm_init_sections
291#undef TARGET_RETURN_IN_MEMORY
292#define TARGET_RETURN_IN_MEMORY mep_return_in_memory
293#undef TARGET_NARROW_VOLATILE_BITFIELD
294#define TARGET_NARROW_VOLATILE_BITFIELD mep_narrow_volatile_bitfield
295#undef TARGET_EXPAND_BUILTIN_SAVEREGS
296#define TARGET_EXPAND_BUILTIN_SAVEREGS mep_expand_builtin_saveregs
297#undef TARGET_BUILD_BUILTIN_VA_LIST
298#define TARGET_BUILD_BUILTIN_VA_LIST mep_build_builtin_va_list
299#undef TARGET_EXPAND_BUILTIN_VA_START
300#define TARGET_EXPAND_BUILTIN_VA_START mep_expand_va_start
301#undef TARGET_GIMPLIFY_VA_ARG_EXPR
302#define TARGET_GIMPLIFY_VA_ARG_EXPR mep_gimplify_va_arg_expr
7b5cbb57
AS
303#undef TARGET_CAN_ELIMINATE
304#define TARGET_CAN_ELIMINATE mep_can_eliminate
7acf4da6
DD
305
306struct gcc_target targetm = TARGET_INITIALIZER;
307\f
308#define WANT_GCC_DEFINITIONS
309#include "mep-intrin.h"
310#undef WANT_GCC_DEFINITIONS
311
312\f
313/* Command Line Option Support. */
314
315char mep_leaf_registers [FIRST_PSEUDO_REGISTER];
316
317/* True if we can use cmov instructions to move values back and forth
318 between core and coprocessor registers. */
319bool mep_have_core_copro_moves_p;
320
321/* True if we can use cmov instructions (or a work-alike) to move
322 values between coprocessor registers. */
323bool mep_have_copro_copro_moves_p;
324
325/* A table of all coprocessor instructions that can act like
326 a coprocessor-to-coprocessor cmov. */
327static const int mep_cmov_insns[] = {
328 mep_cmov,
329 mep_cpmov,
330 mep_fmovs,
331 mep_caddi3,
332 mep_csubi3,
333 mep_candi3,
334 mep_cori3,
335 mep_cxori3,
336 mep_cand3,
337 mep_cor3
338};
339
340static int option_mtiny_specified = 0;
341
342\f
343static void
344mep_set_leaf_registers (int enable)
345{
346 int i;
347
348 if (mep_leaf_registers[0] != enable)
349 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
350 mep_leaf_registers[i] = enable;
351}
352
353void
354mep_conditional_register_usage (char *fixed_regs, char *call_used_regs)
355{
356 int i;
357
358 if (!TARGET_OPT_MULT && !TARGET_OPT_DIV)
359 {
360 fixed_regs[HI_REGNO] = 1;
361 fixed_regs[LO_REGNO] = 1;
362 call_used_regs[HI_REGNO] = 1;
363 call_used_regs[LO_REGNO] = 1;
364 }
365
366 for (i = FIRST_SHADOW_REGISTER; i <= LAST_SHADOW_REGISTER; i++)
367 global_regs[i] = 1;
368}
369
370void
371mep_optimization_options (void)
372{
373 /* The first scheduling pass often increases register pressure and tends
374 to result in more spill code. Only run it when specifically asked. */
375 flag_schedule_insns = 0;
376
377 /* Using $fp doesn't gain us much, even when debugging is important. */
378 flag_omit_frame_pointer = 1;
379}
380
381void
382mep_override_options (void)
383{
384 if (flag_pic == 1)
385 warning (OPT_fpic, "-fpic is not supported");
386 if (flag_pic == 2)
387 warning (OPT_fPIC, "-fPIC is not supported");
388 if (TARGET_S && TARGET_M)
389 error ("only one of -ms and -mm may be given");
390 if (TARGET_S && TARGET_L)
391 error ("only one of -ms and -ml may be given");
392 if (TARGET_M && TARGET_L)
393 error ("only one of -mm and -ml may be given");
394 if (TARGET_S && option_mtiny_specified)
395 error ("only one of -ms and -mtiny= may be given");
396 if (TARGET_M && option_mtiny_specified)
397 error ("only one of -mm and -mtiny= may be given");
398 if (TARGET_OPT_CLIP && ! TARGET_OPT_MINMAX)
399 warning (0, "-mclip currently has no effect without -mminmax");
400
401 if (mep_const_section)
402 {
403 if (strcmp (mep_const_section, "tiny") != 0
404 && strcmp (mep_const_section, "near") != 0
405 && strcmp (mep_const_section, "far") != 0)
406 error ("-mc= must be -mc=tiny, -mc=near, or -mc=far");
407 }
408
409 if (TARGET_S)
410 mep_tiny_cutoff = 65536;
411 if (TARGET_M)
412 mep_tiny_cutoff = 0;
413 if (TARGET_L && ! option_mtiny_specified)
414 mep_tiny_cutoff = 0;
415
416 if (TARGET_64BIT_CR_REGS)
417 flag_split_wide_types = 0;
418
419 init_machine_status = mep_init_machine_status;
420 mep_init_intrinsics ();
421}
422
423/* Pattern Support - constraints, predicates, expanders. */
424
425/* MEP has very few instructions that can refer to the span of
426 addresses used by symbols, so it's common to check for them. */
427
428static bool
429symbol_p (rtx x)
430{
431 int c = GET_CODE (x);
432
433 return (c == CONST_INT
434 || c == CONST
435 || c == SYMBOL_REF);
436}
437
438static bool
439symbolref_p (rtx x)
440{
441 int c;
442
443 if (GET_CODE (x) != MEM)
444 return false;
445
446 c = GET_CODE (XEXP (x, 0));
447 return (c == CONST_INT
448 || c == CONST
449 || c == SYMBOL_REF);
450}
451
452/* static const char *reg_class_names[] = REG_CLASS_NAMES; */
453
454#define GEN_REG(R, STRICT) \
455 (GR_REGNO_P (R) \
456 || (!STRICT \
457 && ((R) == ARG_POINTER_REGNUM \
458 || (R) >= FIRST_PSEUDO_REGISTER)))
459
460static char pattern[12], *patternp;
461static GTY(()) rtx patternr[12];
462#define RTX_IS(x) (strcmp (pattern, x) == 0)
463
464static void
465encode_pattern_1 (rtx x)
466{
467 int i;
468
469 if (patternp == pattern + sizeof (pattern) - 2)
470 {
471 patternp[-1] = '?';
472 return;
473 }
474
475 patternr[patternp-pattern] = x;
476
477 switch (GET_CODE (x))
478 {
479 case REG:
480 *patternp++ = 'r';
481 break;
482 case MEM:
483 *patternp++ = 'm';
484 case CONST:
485 encode_pattern_1 (XEXP(x, 0));
486 break;
487 case PLUS:
488 *patternp++ = '+';
489 encode_pattern_1 (XEXP(x, 0));
490 encode_pattern_1 (XEXP(x, 1));
491 break;
492 case LO_SUM:
493 *patternp++ = 'L';
494 encode_pattern_1 (XEXP(x, 0));
495 encode_pattern_1 (XEXP(x, 1));
496 break;
497 case HIGH:
498 *patternp++ = 'H';
499 encode_pattern_1 (XEXP(x, 0));
500 break;
501 case SYMBOL_REF:
502 *patternp++ = 's';
503 break;
504 case LABEL_REF:
505 *patternp++ = 'l';
506 break;
507 case CONST_INT:
508 case CONST_DOUBLE:
509 *patternp++ = 'i';
510 break;
511 case UNSPEC:
512 *patternp++ = 'u';
513 *patternp++ = '0' + XCINT(x, 1, UNSPEC);
514 for (i=0; i<XVECLEN (x, 0); i++)
515 encode_pattern_1 (XVECEXP (x, 0, i));
516 break;
517 case USE:
518 *patternp++ = 'U';
519 break;
520 default:
521 *patternp++ = '?';
522#if 0
523 fprintf (stderr, "can't encode pattern %s\n", GET_RTX_NAME(GET_CODE(x)));
524 debug_rtx (x);
525 gcc_unreachable ();
526#endif
527 break;
528 }
529}
530
531static void
532encode_pattern (rtx x)
533{
534 patternp = pattern;
535 encode_pattern_1 (x);
536 *patternp = 0;
537}
538
539int
540mep_section_tag (rtx x)
541{
542 const char *name;
543
544 while (1)
545 {
546 switch (GET_CODE (x))
547 {
548 case MEM:
549 case CONST:
550 x = XEXP (x, 0);
551 break;
552 case UNSPEC:
553 x = XVECEXP (x, 0, 0);
554 break;
555 case PLUS:
556 if (GET_CODE (XEXP (x, 1)) != CONST_INT)
557 return 0;
558 x = XEXP (x, 0);
559 break;
560 default:
561 goto done;
562 }
563 }
564 done:
565 if (GET_CODE (x) != SYMBOL_REF)
566 return 0;
567 name = XSTR (x, 0);
568 if (name[0] == '@' && name[2] == '.')
569 {
570 if (name[1] == 'i' || name[1] == 'I')
571 {
572 if (name[1] == 'I')
573 return 'f'; /* near */
574 return 'n'; /* far */
575 }
576 return name[1];
577 }
578 return 0;
579}
580
581int
582mep_regno_reg_class (int regno)
583{
584 switch (regno)
585 {
586 case SP_REGNO: return SP_REGS;
587 case TP_REGNO: return TP_REGS;
588 case GP_REGNO: return GP_REGS;
589 case 0: return R0_REGS;
590 case HI_REGNO: return HI_REGS;
591 case LO_REGNO: return LO_REGS;
592 case ARG_POINTER_REGNUM: return GENERAL_REGS;
593 }
594
595 if (GR_REGNO_P (regno))
596 return regno < FIRST_GR_REGNO + 8 ? TPREL_REGS : GENERAL_REGS;
597 if (CONTROL_REGNO_P (regno))
598 return CONTROL_REGS;
599
600 if (CR_REGNO_P (regno))
601 {
602 int i, j;
603
604 /* Search for the register amongst user-defined subclasses of
605 the coprocessor registers. */
606 for (i = USER0_REGS; i <= USER3_REGS; ++i)
607 {
608 if (! TEST_HARD_REG_BIT (reg_class_contents[i], regno))
609 continue;
610 for (j = 0; j < N_REG_CLASSES; ++j)
611 {
612 enum reg_class sub = reg_class_subclasses[i][j];
613
614 if (sub == LIM_REG_CLASSES)
615 return i;
616 if (TEST_HARD_REG_BIT (reg_class_contents[sub], regno))
617 break;
618 }
619 }
620
621 return LOADABLE_CR_REGNO_P (regno) ? LOADABLE_CR_REGS : CR_REGS;
622 }
623
624 if (CCR_REGNO_P (regno))
625 return CCR_REGS;
626
627 gcc_assert (regno >= FIRST_SHADOW_REGISTER && regno <= LAST_SHADOW_REGISTER);
628 return NO_REGS;
629}
630
631#if 0
632int
633mep_reg_class_from_constraint (int c, const char *str)
634{
635 switch (c)
636 {
637 case 'a':
638 return SP_REGS;
639 case 'b':
640 return TP_REGS;
641 case 'c':
642 return CONTROL_REGS;
643 case 'd':
644 return HILO_REGS;
645 case 'e':
646 {
647 switch (str[1])
648 {
649 case 'm':
650 return LOADABLE_CR_REGS;
651 case 'x':
652 return mep_have_copro_copro_moves_p ? CR_REGS : NO_REGS;
653 case 'r':
654 return mep_have_core_copro_moves_p ? CR_REGS : NO_REGS;
655 default:
656 return NO_REGS;
657 }
658 }
659 case 'h':
660 return HI_REGS;
661 case 'j':
662 return RPC_REGS;
663 case 'l':
664 return LO_REGS;
665 case 't':
666 return TPREL_REGS;
667 case 'v':
668 return GP_REGS;
669 case 'x':
670 return CR_REGS;
671 case 'y':
672 return CCR_REGS;
673 case 'z':
674 return R0_REGS;
675
676 case 'A':
677 case 'B':
678 case 'C':
679 case 'D':
680 {
681 enum reg_class which = c - 'A' + USER0_REGS;
682 return (reg_class_size[which] > 0 ? which : NO_REGS);
683 }
684
685 default:
686 return NO_REGS;
687 }
688}
689
690bool
691mep_const_ok_for_letter_p (HOST_WIDE_INT value, int c)
692{
693 switch (c)
694 {
695 case 'I': return value >= -32768 && value < 32768;
696 case 'J': return value >= 0 && value < 65536;
697 case 'K': return value >= 0 && value < 0x01000000;
698 case 'L': return value >= -32 && value < 32;
699 case 'M': return value >= 0 && value < 32;
700 case 'N': return value >= 0 && value < 16;
701 case 'O':
702 if (value & 0xffff)
703 return false;
704 return value >= -2147483647-1 && value <= 2147483647;
705 default:
706 gcc_unreachable ();
707 }
708}
709
710bool
711mep_extra_constraint (rtx value, int c)
712{
713 encode_pattern (value);
714
715 switch (c)
716 {
717 case 'R':
718 /* For near symbols, like what call uses. */
719 if (GET_CODE (value) == REG)
720 return 0;
721 return mep_call_address_operand (value, GET_MODE (value));
722
723 case 'S':
724 /* For signed 8-bit immediates. */
725 return (GET_CODE (value) == CONST_INT
726 && INTVAL (value) >= -128
727 && INTVAL (value) <= 127);
728
729 case 'T':
730 /* For tp/gp relative symbol values. */
731 return (RTX_IS ("u3s") || RTX_IS ("u2s")
732 || RTX_IS ("+u3si") || RTX_IS ("+u2si"));
733
734 case 'U':
735 /* Non-absolute memories. */
736 return GET_CODE (value) == MEM && ! CONSTANT_P (XEXP (value, 0));
737
738 case 'W':
739 /* %hi(sym) */
740 return RTX_IS ("Hs");
741
742 case 'Y':
743 /* Register indirect. */
744 return RTX_IS ("mr");
745
746 case 'Z':
747 return mep_section_tag (value) == 'c' && RTX_IS ("ms");
748 }
749
750 return false;
751}
752#endif
753
754#undef PASS
755#undef FAIL
756
757static bool
758const_in_range (rtx x, int minv, int maxv)
759{
760 return (GET_CODE (x) == CONST_INT
761 && INTVAL (x) >= minv
762 && INTVAL (x) <= maxv);
763}
764
765/* Given three integer registers DEST, SRC1 and SRC2, return an rtx X
766 such that "mulr DEST,X" will calculate DEST = SRC1 * SRC2. If a move
767 is needed, emit it before INSN if INSN is nonnull, otherwise emit it
768 at the end of the insn stream. */
769
770rtx
771mep_mulr_source (rtx insn, rtx dest, rtx src1, rtx src2)
772{
773 if (rtx_equal_p (dest, src1))
774 return src2;
775 else if (rtx_equal_p (dest, src2))
776 return src1;
777 else
778 {
779 if (insn == 0)
780 emit_insn (gen_movsi (copy_rtx (dest), src1));
781 else
782 emit_insn_before (gen_movsi (copy_rtx (dest), src1), insn);
783 return src2;
784 }
785}
786
787/* Replace INSN's pattern with PATTERN, a multiplication PARALLEL.
788 Change the last element of PATTERN from (clobber (scratch:SI))
789 to (clobber (reg:SI HI_REGNO)). */
790
791static void
792mep_rewrite_mult (rtx insn, rtx pattern)
793{
794 rtx hi_clobber;
795
796 hi_clobber = XVECEXP (pattern, 0, XVECLEN (pattern, 0) - 1);
797 XEXP (hi_clobber, 0) = gen_rtx_REG (SImode, HI_REGNO);
798 PATTERN (insn) = pattern;
799 INSN_CODE (insn) = -1;
800}
801
802/* Subroutine of mep_reuse_lo_p. Rewrite instruction INSN so that it
803 calculates SRC1 * SRC2 and stores the result in $lo. Also make it
804 store the result in DEST if nonnull. */
805
806static void
807mep_rewrite_mulsi3 (rtx insn, rtx dest, rtx src1, rtx src2)
808{
809 rtx lo, pattern;
810
811 lo = gen_rtx_REG (SImode, LO_REGNO);
812 if (dest)
813 pattern = gen_mulsi3r (lo, dest, copy_rtx (dest),
814 mep_mulr_source (insn, dest, src1, src2));
815 else
816 pattern = gen_mulsi3_lo (lo, src1, src2);
817 mep_rewrite_mult (insn, pattern);
818}
819
820/* Like mep_rewrite_mulsi3, but calculate SRC1 * SRC2 + SRC3. First copy
821 SRC3 into $lo, then use either madd or maddr. The move into $lo will
822 be deleted by a peephole2 if SRC3 is already in $lo. */
823
824static void
825mep_rewrite_maddsi3 (rtx insn, rtx dest, rtx src1, rtx src2, rtx src3)
826{
827 rtx lo, pattern;
828
829 lo = gen_rtx_REG (SImode, LO_REGNO);
830 emit_insn_before (gen_movsi (copy_rtx (lo), src3), insn);
831 if (dest)
832 pattern = gen_maddsi3r (lo, dest, copy_rtx (dest),
833 mep_mulr_source (insn, dest, src1, src2),
834 copy_rtx (lo));
835 else
836 pattern = gen_maddsi3_lo (lo, src1, src2, copy_rtx (lo));
837 mep_rewrite_mult (insn, pattern);
838}
839
840/* Return true if $lo has the same value as integer register GPR when
841 instruction INSN is reached. If necessary, rewrite the instruction
842 that sets $lo so that it uses a proper SET, not a CLOBBER. LO is an
843 rtx for (reg:SI LO_REGNO).
844
845 This function is intended to be used by the peephole2 pass. Since
846 that pass goes from the end of a basic block to the beginning, and
847 propagates liveness information on the way, there is no need to
848 update register notes here.
849
850 If GPR_DEAD_P is true on entry, and this function returns true,
851 then the caller will replace _every_ use of GPR in and after INSN
852 with LO. This means that if the instruction that sets $lo is a
853 mulr- or maddr-type instruction, we can rewrite it to use mul or
854 madd instead. In combination with the copy progagation pass,
855 this allows us to replace sequences like:
856
857 mov GPR,R1
858 mulr GPR,R2
859
860 with:
861
862 mul R1,R2
863
864 if GPR is no longer used. */
865
866static bool
867mep_reuse_lo_p_1 (rtx lo, rtx gpr, rtx insn, bool gpr_dead_p)
868{
869 do
870 {
871 insn = PREV_INSN (insn);
872 if (INSN_P (insn))
873 switch (recog_memoized (insn))
874 {
875 case CODE_FOR_mulsi3_1:
876 extract_insn (insn);
877 if (rtx_equal_p (recog_data.operand[0], gpr))
878 {
879 mep_rewrite_mulsi3 (insn,
880 gpr_dead_p ? NULL : recog_data.operand[0],
881 recog_data.operand[1],
882 recog_data.operand[2]);
883 return true;
884 }
885 return false;
886
887 case CODE_FOR_maddsi3:
888 extract_insn (insn);
889 if (rtx_equal_p (recog_data.operand[0], gpr))
890 {
891 mep_rewrite_maddsi3 (insn,
892 gpr_dead_p ? NULL : recog_data.operand[0],
893 recog_data.operand[1],
894 recog_data.operand[2],
895 recog_data.operand[3]);
896 return true;
897 }
898 return false;
899
900 case CODE_FOR_mulsi3r:
901 case CODE_FOR_maddsi3r:
902 extract_insn (insn);
903 return rtx_equal_p (recog_data.operand[1], gpr);
904
905 default:
906 if (reg_set_p (lo, insn)
907 || reg_set_p (gpr, insn)
908 || volatile_insn_p (PATTERN (insn)))
909 return false;
910
911 if (gpr_dead_p && reg_referenced_p (gpr, PATTERN (insn)))
912 gpr_dead_p = false;
913 break;
914 }
915 }
916 while (!NOTE_INSN_BASIC_BLOCK_P (insn));
917 return false;
918}
919
920/* A wrapper around mep_reuse_lo_p_1 that preserves recog_data. */
921
922bool
923mep_reuse_lo_p (rtx lo, rtx gpr, rtx insn, bool gpr_dead_p)
924{
925 bool result = mep_reuse_lo_p_1 (lo, gpr, insn, gpr_dead_p);
926 extract_insn (insn);
927 return result;
928}
929
930/* Return true if SET can be turned into a post-modify load or store
931 that adds OFFSET to GPR. In other words, return true if SET can be
932 changed into:
933
934 (parallel [SET (set GPR (plus:SI GPR OFFSET))]).
935
936 It's OK to change SET to an equivalent operation in order to
937 make it match. */
938
939static bool
940mep_use_post_modify_for_set_p (rtx set, rtx gpr, rtx offset)
941{
942 rtx *reg, *mem;
943 unsigned int reg_bytes, mem_bytes;
944 enum machine_mode reg_mode, mem_mode;
945
946 /* Only simple SETs can be converted. */
947 if (GET_CODE (set) != SET)
948 return false;
949
950 /* Point REG to what we hope will be the register side of the set and
951 MEM to what we hope will be the memory side. */
952 if (GET_CODE (SET_DEST (set)) == MEM)
953 {
954 mem = &SET_DEST (set);
955 reg = &SET_SRC (set);
956 }
957 else
958 {
959 reg = &SET_DEST (set);
960 mem = &SET_SRC (set);
961 if (GET_CODE (*mem) == SIGN_EXTEND)
962 mem = &XEXP (*mem, 0);
963 }
964
965 /* Check that *REG is a suitable coprocessor register. */
966 if (GET_CODE (*reg) != REG || !LOADABLE_CR_REGNO_P (REGNO (*reg)))
967 return false;
968
969 /* Check that *MEM is a suitable memory reference. */
970 if (GET_CODE (*mem) != MEM || !rtx_equal_p (XEXP (*mem, 0), gpr))
971 return false;
972
973 /* Get the number of bytes in each operand. */
974 mem_bytes = GET_MODE_SIZE (GET_MODE (*mem));
975 reg_bytes = GET_MODE_SIZE (GET_MODE (*reg));
976
977 /* Check that OFFSET is suitably aligned. */
978 if (INTVAL (offset) & (mem_bytes - 1))
979 return false;
980
981 /* Convert *MEM to a normal integer mode. */
982 mem_mode = mode_for_size (mem_bytes * BITS_PER_UNIT, MODE_INT, 0);
983 *mem = change_address (*mem, mem_mode, NULL);
984
985 /* Adjust *REG as well. */
986 *reg = shallow_copy_rtx (*reg);
987 if (reg == &SET_DEST (set) && reg_bytes < UNITS_PER_WORD)
988 {
989 /* SET is a subword load. Convert it to an explicit extension. */
990 PUT_MODE (*reg, SImode);
991 *mem = gen_rtx_SIGN_EXTEND (SImode, *mem);
992 }
993 else
994 {
995 reg_mode = mode_for_size (reg_bytes * BITS_PER_UNIT, MODE_INT, 0);
996 PUT_MODE (*reg, reg_mode);
997 }
998 return true;
999}
1000
1001/* Return the effect of frame-related instruction INSN. */
1002
1003static rtx
1004mep_frame_expr (rtx insn)
1005{
1006 rtx note, expr;
1007
1008 note = find_reg_note (insn, REG_FRAME_RELATED_EXPR, 0);
1009 expr = (note != 0 ? XEXP (note, 0) : copy_rtx (PATTERN (insn)));
1010 RTX_FRAME_RELATED_P (expr) = 1;
1011 return expr;
1012}
1013
1014/* Merge instructions INSN1 and INSN2 using a PARALLEL. Store the
1015 new pattern in INSN1; INSN2 will be deleted by the caller. */
1016
1017static void
1018mep_make_parallel (rtx insn1, rtx insn2)
1019{
1020 rtx expr;
1021
1022 if (RTX_FRAME_RELATED_P (insn2))
1023 {
1024 expr = mep_frame_expr (insn2);
1025 if (RTX_FRAME_RELATED_P (insn1))
1026 expr = gen_rtx_SEQUENCE (VOIDmode,
1027 gen_rtvec (2, mep_frame_expr (insn1), expr));
1028 set_unique_reg_note (insn1, REG_FRAME_RELATED_EXPR, expr);
1029 RTX_FRAME_RELATED_P (insn1) = 1;
1030 }
1031
1032 PATTERN (insn1) = gen_rtx_PARALLEL (VOIDmode,
1033 gen_rtvec (2, PATTERN (insn1),
1034 PATTERN (insn2)));
1035 INSN_CODE (insn1) = -1;
1036}
1037
1038/* SET_INSN is an instruction that adds OFFSET to REG. Go back through
1039 the basic block to see if any previous load or store instruction can
1040 be persuaded to do SET_INSN as a side-effect. Return true if so. */
1041
1042static bool
1043mep_use_post_modify_p_1 (rtx set_insn, rtx reg, rtx offset)
1044{
1045 rtx insn;
1046
1047 insn = set_insn;
1048 do
1049 {
1050 insn = PREV_INSN (insn);
1051 if (INSN_P (insn))
1052 {
1053 if (mep_use_post_modify_for_set_p (PATTERN (insn), reg, offset))
1054 {
1055 mep_make_parallel (insn, set_insn);
1056 return true;
1057 }
1058
1059 if (reg_set_p (reg, insn)
1060 || reg_referenced_p (reg, PATTERN (insn))
1061 || volatile_insn_p (PATTERN (insn)))
1062 return false;
1063 }
1064 }
1065 while (!NOTE_INSN_BASIC_BLOCK_P (insn));
1066 return false;
1067}
1068
1069/* A wrapper around mep_use_post_modify_p_1 that preserves recog_data. */
1070
1071bool
1072mep_use_post_modify_p (rtx insn, rtx reg, rtx offset)
1073{
1074 bool result = mep_use_post_modify_p_1 (insn, reg, offset);
1075 extract_insn (insn);
1076 return result;
1077}
1078
1079bool
1080mep_allow_clip (rtx ux, rtx lx, int s)
1081{
1082 HOST_WIDE_INT u = INTVAL (ux);
1083 HOST_WIDE_INT l = INTVAL (lx);
1084 int i;
1085
1086 if (!TARGET_OPT_CLIP)
1087 return false;
1088
1089 if (s)
1090 {
1091 for (i = 0; i < 30; i ++)
1092 if ((u == ((HOST_WIDE_INT) 1 << i) - 1)
1093 && (l == - ((HOST_WIDE_INT) 1 << i)))
1094 return true;
1095 }
1096 else
1097 {
1098 if (l != 0)
1099 return false;
1100
1101 for (i = 0; i < 30; i ++)
1102 if ((u == ((HOST_WIDE_INT) 1 << i) - 1))
1103 return true;
1104 }
1105 return false;
1106}
1107
1108bool
1109mep_bit_position_p (rtx x, bool looking_for)
1110{
1111 if (GET_CODE (x) != CONST_INT)
1112 return false;
1113 switch ((int) INTVAL(x) & 0xff)
1114 {
1115 case 0x01: case 0x02: case 0x04: case 0x08:
1116 case 0x10: case 0x20: case 0x40: case 0x80:
1117 return looking_for;
1118 case 0xfe: case 0xfd: case 0xfb: case 0xf7:
1119 case 0xef: case 0xdf: case 0xbf: case 0x7f:
1120 return !looking_for;
1121 }
1122 return false;
1123}
1124
1125static bool
1126move_needs_splitting (rtx dest, rtx src,
1127 enum machine_mode mode ATTRIBUTE_UNUSED)
1128{
1129 int s = mep_section_tag (src);
1130
1131 while (1)
1132 {
1133 if (GET_CODE (src) == CONST
1134 || GET_CODE (src) == MEM)
1135 src = XEXP (src, 0);
1136 else if (GET_CODE (src) == SYMBOL_REF
1137 || GET_CODE (src) == LABEL_REF
1138 || GET_CODE (src) == PLUS)
1139 break;
1140 else
1141 return false;
1142 }
1143 if (s == 'f'
1144 || (GET_CODE (src) == PLUS
1145 && GET_CODE (XEXP (src, 1)) == CONST_INT
1146 && (INTVAL (XEXP (src, 1)) < -65536
1147 || INTVAL (XEXP (src, 1)) > 0xffffff))
1148 || (GET_CODE (dest) == REG
1149 && REGNO (dest) > 7 && REGNO (dest) < FIRST_PSEUDO_REGISTER))
1150 return true;
1151 return false;
1152}
1153
1154bool
1155mep_split_mov (rtx *operands, int symbolic)
1156{
1157 if (symbolic)
1158 {
1159 if (move_needs_splitting (operands[0], operands[1], SImode))
1160 return true;
1161 return false;
1162 }
1163
1164 if (GET_CODE (operands[1]) != CONST_INT)
1165 return false;
1166
1167 if (constraint_satisfied_p (operands[1], CONSTRAINT_I)
1168 || constraint_satisfied_p (operands[1], CONSTRAINT_J)
1169 || constraint_satisfied_p (operands[1], CONSTRAINT_O))
1170 return false;
1171
1172 if (((!reload_completed && !reload_in_progress)
1173 || (REG_P (operands[0]) && REGNO (operands[0]) < 8))
1174 && constraint_satisfied_p (operands[1], CONSTRAINT_K))
1175 return false;
1176
1177 return true;
1178}
1179
1180/* Irritatingly, the "jsrv" insn *toggles* PSW.OM rather than set
1181 it to one specific value. So the insn chosen depends on whether
1182 the source and destination modes match. */
1183
1184bool
1185mep_vliw_mode_match (rtx tgt)
1186{
1187 bool src_vliw = mep_vliw_function_p (cfun->decl);
1188 bool tgt_vliw = INTVAL (tgt);
1189
1190 return src_vliw == tgt_vliw;
1191}
1192
a9d1723f
DD
1193/* Like the above, but also test for near/far mismatches. */
1194
1195bool
1196mep_vliw_jmp_match (rtx tgt)
1197{
1198 bool src_vliw = mep_vliw_function_p (cfun->decl);
1199 bool tgt_vliw = INTVAL (tgt);
1200
1201 if (mep_section_tag (DECL_RTL (cfun->decl)) == 'f')
1202 return false;
1203
1204 return src_vliw == tgt_vliw;
1205}
1206
7acf4da6
DD
1207bool
1208mep_multi_slot (rtx x)
1209{
1210 return get_attr_slot (x) == SLOT_MULTI;
1211}
1212
1213
1214/* Be careful not to use macros that need to be compiled one way for
1215 strict, and another way for not-strict, like REG_OK_FOR_BASE_P. */
1216
1217bool
1218mep_legitimate_address (enum machine_mode mode, rtx x, int strict)
1219{
1220 int the_tag;
1221
1222#define DEBUG_LEGIT 0
1223#if DEBUG_LEGIT
1224 fprintf (stderr, "legit: mode %s strict %d ", mode_name[mode], strict);
1225 debug_rtx (x);
1226#endif
1227
1228 if (GET_CODE (x) == LO_SUM
1229 && GET_CODE (XEXP (x, 0)) == REG
1230 && GEN_REG (REGNO (XEXP (x, 0)), strict)
1231 && CONSTANT_P (XEXP (x, 1)))
1232 {
1233 if (GET_MODE_SIZE (mode) > 4)
1234 {
1235 /* We will end up splitting this, and lo_sums are not
1236 offsettable for us. */
1237#if DEBUG_LEGIT
1238 fprintf(stderr, " - nope, %%lo(sym)[reg] not splittable\n");
1239#endif
1240 return false;
1241 }
1242#if DEBUG_LEGIT
1243 fprintf (stderr, " - yup, %%lo(sym)[reg]\n");
1244#endif
1245 return true;
1246 }
1247
1248 if (GET_CODE (x) == REG
1249 && GEN_REG (REGNO (x), strict))
1250 {
1251#if DEBUG_LEGIT
1252 fprintf (stderr, " - yup, [reg]\n");
1253#endif
1254 return true;
1255 }
1256
1257 if (GET_CODE (x) == PLUS
1258 && GET_CODE (XEXP (x, 0)) == REG
1259 && GEN_REG (REGNO (XEXP (x, 0)), strict)
1260 && const_in_range (XEXP (x, 1), -32768, 32767))
1261 {
1262#if DEBUG_LEGIT
1263 fprintf (stderr, " - yup, [reg+const]\n");
1264#endif
1265 return true;
1266 }
1267
1268 if (GET_CODE (x) == PLUS
1269 && GET_CODE (XEXP (x, 0)) == REG
1270 && GEN_REG (REGNO (XEXP (x, 0)), strict)
1271 && GET_CODE (XEXP (x, 1)) == CONST
1272 && (GET_CODE (XEXP (XEXP (x, 1), 0)) == UNSPEC
1273 || (GET_CODE (XEXP (XEXP (x, 1), 0)) == PLUS
1274 && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 0)) == UNSPEC
1275 && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 1)) == CONST_INT)))
1276 {
1277#if DEBUG_LEGIT
1278 fprintf (stderr, " - yup, [reg+unspec]\n");
1279#endif
1280 return true;
1281 }
1282
1283 the_tag = mep_section_tag (x);
1284
1285 if (the_tag == 'f')
1286 {
1287#if DEBUG_LEGIT
1288 fprintf (stderr, " - nope, [far]\n");
1289#endif
1290 return false;
1291 }
1292
1293 if (mode == VOIDmode
1294 && GET_CODE (x) == SYMBOL_REF)
1295 {
1296#if DEBUG_LEGIT
1297 fprintf (stderr, " - yup, call [symbol]\n");
1298#endif
1299 return true;
1300 }
1301
1302 if ((mode == SImode || mode == SFmode)
1303 && CONSTANT_P (x)
1304 && LEGITIMATE_CONSTANT_P (x)
1305 && the_tag != 't' && the_tag != 'b')
1306 {
1307 if (GET_CODE (x) != CONST_INT
1308 || (INTVAL (x) <= 0xfffff
1309 && INTVAL (x) >= 0
1310 && (INTVAL (x) % 4) == 0))
1311 {
1312#if DEBUG_LEGIT
1313 fprintf (stderr, " - yup, [const]\n");
1314#endif
1315 return true;
1316 }
1317 }
1318
1319#if DEBUG_LEGIT
1320 fprintf (stderr, " - nope.\n");
1321#endif
1322 return false;
1323}
1324
1325int
1326mep_legitimize_reload_address (rtx *x, enum machine_mode mode, int opnum,
1327 enum reload_type type,
1328 int ind_levels ATTRIBUTE_UNUSED)
1329{
1330 if (GET_CODE (*x) == PLUS
1331 && GET_CODE (XEXP (*x, 0)) == MEM
1332 && GET_CODE (XEXP (*x, 1)) == REG)
1333 {
1334 /* GCC will by default copy the MEM into a REG, which results in
1335 an invalid address. For us, the best thing to do is move the
1336 whole expression to a REG. */
1337 push_reload (*x, NULL_RTX, x, NULL,
1338 GENERAL_REGS, mode, VOIDmode,
1339 0, 0, opnum, type);
1340 return 1;
1341 }
1342
1343 if (GET_CODE (*x) == PLUS
1344 && GET_CODE (XEXP (*x, 0)) == SYMBOL_REF
1345 && GET_CODE (XEXP (*x, 1)) == CONST_INT)
1346 {
1347 char e = mep_section_tag (XEXP (*x, 0));
1348
1349 if (e != 't' && e != 'b')
1350 {
1351 /* GCC thinks that (sym+const) is a valid address. Well,
1352 sometimes it is, this time it isn't. The best thing to
1353 do is reload the symbol to a register, since reg+int
1354 tends to work, and we can't just add the symbol and
1355 constant anyway. */
1356 push_reload (XEXP (*x, 0), NULL_RTX, &(XEXP(*x, 0)), NULL,
1357 GENERAL_REGS, mode, VOIDmode,
1358 0, 0, opnum, type);
1359 return 1;
1360 }
1361 }
1362 return 0;
1363}
1364
1365int
1366mep_core_address_length (rtx insn, int opn)
1367{
1368 rtx set = single_set (insn);
1369 rtx mem = XEXP (set, opn);
1370 rtx other = XEXP (set, 1-opn);
1371 rtx addr = XEXP (mem, 0);
1372
1373 if (register_operand (addr, Pmode))
1374 return 2;
1375 if (GET_CODE (addr) == PLUS)
1376 {
1377 rtx addend = XEXP (addr, 1);
1378
1379 gcc_assert (REG_P (XEXP (addr, 0)));
1380
1381 switch (REGNO (XEXP (addr, 0)))
1382 {
1383 case STACK_POINTER_REGNUM:
1384 if (GET_MODE_SIZE (GET_MODE (mem)) == 4
1385 && mep_imm7a4_operand (addend, VOIDmode))
1386 return 2;
1387 break;
1388
1389 case 13: /* TP */
1390 gcc_assert (REG_P (other));
1391
1392 if (REGNO (other) >= 8)
1393 break;
1394
1395 if (GET_CODE (addend) == CONST
1396 && GET_CODE (XEXP (addend, 0)) == UNSPEC
1397 && XINT (XEXP (addend, 0), 1) == UNS_TPREL)
1398 return 2;
1399
1400 if (GET_CODE (addend) == CONST_INT
1401 && INTVAL (addend) >= 0
1402 && INTVAL (addend) <= 127
1403 && INTVAL (addend) % GET_MODE_SIZE (GET_MODE (mem)) == 0)
1404 return 2;
1405 break;
1406 }
1407 }
1408
1409 return 4;
1410}
1411
1412int
1413mep_cop_address_length (rtx insn, int opn)
1414{
1415 rtx set = single_set (insn);
1416 rtx mem = XEXP (set, opn);
1417 rtx addr = XEXP (mem, 0);
1418
1419 if (GET_CODE (mem) != MEM)
1420 return 2;
1421 if (register_operand (addr, Pmode))
1422 return 2;
1423 if (GET_CODE (addr) == POST_INC)
1424 return 2;
1425
1426 return 4;
1427}
1428
1429#define DEBUG_EXPAND_MOV 0
1430bool
1431mep_expand_mov (rtx *operands, enum machine_mode mode)
1432{
1433 int i, t;
1434 int tag[2];
1435 rtx tpsym, tpoffs;
1436 int post_reload = 0;
1437
1438 tag[0] = mep_section_tag (operands[0]);
1439 tag[1] = mep_section_tag (operands[1]);
1440
1441 if (!reload_in_progress
1442 && !reload_completed
1443 && GET_CODE (operands[0]) != REG
1444 && GET_CODE (operands[0]) != SUBREG
1445 && GET_CODE (operands[1]) != REG
1446 && GET_CODE (operands[1]) != SUBREG)
1447 operands[1] = copy_to_mode_reg (mode, operands[1]);
1448
1449#if DEBUG_EXPAND_MOV
1450 fprintf(stderr, "expand move %s %d\n", mode_name[mode],
1451 reload_in_progress || reload_completed);
1452 debug_rtx (operands[0]);
1453 debug_rtx (operands[1]);
1454#endif
1455
1456 if (mode == DImode || mode == DFmode)
1457 return false;
1458
1459 if (reload_in_progress || reload_completed)
1460 {
1461 rtx r;
1462
1463 if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == TP_REGNO)
1464 cfun->machine->reload_changes_tp = true;
1465
1466 if (tag[0] == 't' || tag[1] == 't')
1467 {
1468 r = has_hard_reg_initial_val (Pmode, GP_REGNO);
1469 if (!r || GET_CODE (r) != REG || REGNO (r) != GP_REGNO)
1470 post_reload = 1;
1471 }
1472 if (tag[0] == 'b' || tag[1] == 'b')
1473 {
1474 r = has_hard_reg_initial_val (Pmode, TP_REGNO);
1475 if (!r || GET_CODE (r) != REG || REGNO (r) != TP_REGNO)
1476 post_reload = 1;
1477 }
1478 if (cfun->machine->reload_changes_tp == true)
1479 post_reload = 1;
1480 }
1481
1482 if (!post_reload)
1483 {
1484 rtx n;
1485 if (symbol_p (operands[1]))
1486 {
1487 t = mep_section_tag (operands[1]);
1488 if (t == 'b' || t == 't')
1489 {
1490
1491 if (GET_CODE (operands[1]) == SYMBOL_REF)
1492 {
1493 tpsym = operands[1];
1494 n = gen_rtx_UNSPEC (mode,
1495 gen_rtvec (1, operands[1]),
1496 t == 'b' ? UNS_TPREL : UNS_GPREL);
1497 n = gen_rtx_CONST (mode, n);
1498 }
1499 else if (GET_CODE (operands[1]) == CONST
1500 && GET_CODE (XEXP (operands[1], 0)) == PLUS
1501 && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == SYMBOL_REF
1502 && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT)
1503 {
1504 tpsym = XEXP (XEXP (operands[1], 0), 0);
1505 tpoffs = XEXP (XEXP (operands[1], 0), 1);
1506 n = gen_rtx_UNSPEC (mode,
1507 gen_rtvec (1, tpsym),
1508 t == 'b' ? UNS_TPREL : UNS_GPREL);
1509 n = gen_rtx_PLUS (mode, n, tpoffs);
1510 n = gen_rtx_CONST (mode, n);
1511 }
1512 else if (GET_CODE (operands[1]) == CONST
1513 && GET_CODE (XEXP (operands[1], 0)) == UNSPEC)
1514 return false;
1515 else
1516 {
1517 error ("unusual TP-relative address");
1518 return false;
1519 }
1520
1521 n = gen_rtx_PLUS (mode, (t == 'b' ? mep_tp_rtx ()
1522 : mep_gp_rtx ()), n);
1523 n = emit_insn (gen_rtx_SET (mode, operands[0], n));
1524#if DEBUG_EXPAND_MOV
1525 fprintf(stderr, "mep_expand_mov emitting ");
1526 debug_rtx(n);
1527#endif
1528 return true;
1529 }
1530 }
1531
1532 for (i=0; i < 2; i++)
1533 {
1534 t = mep_section_tag (operands[i]);
1535 if (GET_CODE (operands[i]) == MEM && (t == 'b' || t == 't'))
1536 {
1537 rtx sym, n, r;
1538 int u;
1539
1540 sym = XEXP (operands[i], 0);
1541 if (GET_CODE (sym) == CONST
1542 && GET_CODE (XEXP (sym, 0)) == UNSPEC)
1543 sym = XVECEXP (XEXP (sym, 0), 0, 0);
1544
1545 if (t == 'b')
1546 {
1547 r = mep_tp_rtx ();
1548 u = UNS_TPREL;
1549 }
1550 else
1551 {
1552 r = mep_gp_rtx ();
1553 u = UNS_GPREL;
1554 }
1555
1556 n = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), u);
1557 n = gen_rtx_CONST (Pmode, n);
1558 n = gen_rtx_PLUS (Pmode, r, n);
1559 operands[i] = replace_equiv_address (operands[i], n);
1560 }
1561 }
1562 }
1563
1564 if ((GET_CODE (operands[1]) != REG
1565 && MEP_CONTROL_REG (operands[0]))
1566 || (GET_CODE (operands[0]) != REG
1567 && MEP_CONTROL_REG (operands[1])))
1568 {
1569 rtx temp;
1570#if DEBUG_EXPAND_MOV
1571 fprintf (stderr, "cr-mem, forcing op1 to reg\n");
1572#endif
1573 temp = gen_reg_rtx (mode);
1574 emit_move_insn (temp, operands[1]);
1575 operands[1] = temp;
1576 }
1577
1578 if (symbolref_p (operands[0])
1579 && (mep_section_tag (XEXP (operands[0], 0)) == 'f'
1580 || (GET_MODE_SIZE (mode) != 4)))
1581 {
1582 rtx temp;
1583
1584 gcc_assert (!reload_in_progress && !reload_completed);
1585
1586 temp = force_reg (Pmode, XEXP (operands[0], 0));
1587 operands[0] = replace_equiv_address (operands[0], temp);
1588 emit_move_insn (operands[0], operands[1]);
1589 return true;
1590 }
1591
1592 if (!post_reload && (tag[1] == 't' || tag[1] == 'b'))
1593 tag[1] = 0;
1594
1595 if (symbol_p (operands[1])
1596 && (tag[1] == 'f' || tag[1] == 't' || tag[1] == 'b'))
1597 {
1598 emit_insn (gen_movsi_topsym_s (operands[0], operands[1]));
1599 emit_insn (gen_movsi_botsym_s (operands[0], operands[0], operands[1]));
1600 return true;
1601 }
1602
1603 if (symbolref_p (operands[1])
1604 && (tag[1] == 'f' || tag[1] == 't' || tag[1] == 'b'))
1605 {
1606 rtx temp;
1607
1608 if (reload_in_progress || reload_completed)
1609 temp = operands[0];
1610 else
1611 temp = gen_reg_rtx (Pmode);
1612
1613 emit_insn (gen_movsi_topsym_s (temp, operands[1]));
1614 emit_insn (gen_movsi_botsym_s (temp, temp, operands[1]));
1615 emit_move_insn (operands[0], replace_equiv_address (operands[1], temp));
1616 return true;
1617 }
1618
1619 return false;
1620}
1621
1622/* Cases where the pattern can't be made to use at all. */
1623
1624bool
1625mep_mov_ok (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
1626{
1627 int i;
1628
1629#define DEBUG_MOV_OK 0
1630#if DEBUG_MOV_OK
1631 fprintf (stderr, "mep_mov_ok %s %c=%c\n", mode_name[mode], mep_section_tag (operands[0]),
1632 mep_section_tag (operands[1]));
1633 debug_rtx (operands[0]);
1634 debug_rtx (operands[1]);
1635#endif
1636
1637 /* We want the movh patterns to get these. */
1638 if (GET_CODE (operands[1]) == HIGH)
1639 return false;
1640
1641 /* We can't store a register to a far variable without using a
1642 scratch register to hold the address. Using far variables should
1643 be split by mep_emit_mov anyway. */
1644 if (mep_section_tag (operands[0]) == 'f'
1645 || mep_section_tag (operands[1]) == 'f')
1646 {
1647#if DEBUG_MOV_OK
1648 fprintf (stderr, " - no, f\n");
1649#endif
1650 return false;
1651 }
1652 i = mep_section_tag (operands[1]);
1653 if ((i == 'b' || i == 't') && !reload_completed && !reload_in_progress)
1654 /* These are supposed to be generated with adds of the appropriate
1655 register. During and after reload, however, we allow them to
1656 be accessed as normal symbols because adding a dependency on
1657 the base register now might cause problems. */
1658 {
1659#if DEBUG_MOV_OK
1660 fprintf (stderr, " - no, bt\n");
1661#endif
1662 return false;
1663 }
1664
1665 /* The only moves we can allow involve at least one general
1666 register, so require it. */
1667 for (i = 0; i < 2; i ++)
1668 {
1669 /* Allow subregs too, before reload. */
1670 rtx x = operands[i];
1671
1672 if (GET_CODE (x) == SUBREG)
1673 x = XEXP (x, 0);
1674 if (GET_CODE (x) == REG
1675 && ! MEP_CONTROL_REG (x))
1676 {
1677#if DEBUG_MOV_OK
1678 fprintf (stderr, " - ok\n");
1679#endif
1680 return true;
1681 }
1682 }
1683#if DEBUG_MOV_OK
1684 fprintf (stderr, " - no, no gen reg\n");
1685#endif
1686 return false;
1687}
1688
1689#define DEBUG_SPLIT_WIDE_MOVE 0
1690void
1691mep_split_wide_move (rtx *operands, enum machine_mode mode)
1692{
1693 int i;
1694
1695#if DEBUG_SPLIT_WIDE_MOVE
1696 fprintf (stderr, "\n\033[34mmep_split_wide_move\033[0m mode %s\n", mode_name[mode]);
1697 debug_rtx (operands[0]);
1698 debug_rtx (operands[1]);
1699#endif
1700
1701 for (i = 0; i <= 1; i++)
1702 {
1703 rtx op = operands[i], hi, lo;
1704
1705 switch (GET_CODE (op))
1706 {
1707 case REG:
1708 {
1709 unsigned int regno = REGNO (op);
1710
1711 if (TARGET_64BIT_CR_REGS && CR_REGNO_P (regno))
1712 {
1713 rtx i32;
1714
1715 lo = gen_rtx_REG (SImode, regno);
1716 i32 = GEN_INT (32);
1717 hi = gen_rtx_ZERO_EXTRACT (SImode,
1718 gen_rtx_REG (DImode, regno),
1719 i32, i32);
1720 }
1721 else
1722 {
1723 hi = gen_rtx_REG (SImode, regno + TARGET_LITTLE_ENDIAN);
1724 lo = gen_rtx_REG (SImode, regno + TARGET_BIG_ENDIAN);
1725 }
1726 }
1727 break;
1728
1729 case CONST_INT:
1730 case CONST_DOUBLE:
1731 case MEM:
1732 hi = operand_subword (op, TARGET_LITTLE_ENDIAN, 0, mode);
1733 lo = operand_subword (op, TARGET_BIG_ENDIAN, 0, mode);
1734 break;
1735
1736 default:
1737 gcc_unreachable ();
1738 }
1739
1740 /* The high part of CR <- GPR moves must be done after the low part. */
1741 operands [i + 4] = lo;
1742 operands [i + 2] = hi;
1743 }
1744
1745 if (reg_mentioned_p (operands[2], operands[5])
1746 || GET_CODE (operands[2]) == ZERO_EXTRACT
1747 || GET_CODE (operands[4]) == ZERO_EXTRACT)
1748 {
1749 rtx tmp;
1750
1751 /* Overlapping register pairs -- make sure we don't
1752 early-clobber ourselves. */
1753 tmp = operands[2];
1754 operands[2] = operands[4];
1755 operands[4] = tmp;
1756 tmp = operands[3];
1757 operands[3] = operands[5];
1758 operands[5] = tmp;
1759 }
1760
1761#if DEBUG_SPLIT_WIDE_MOVE
1762 fprintf(stderr, "\033[34m");
1763 debug_rtx (operands[2]);
1764 debug_rtx (operands[3]);
1765 debug_rtx (operands[4]);
1766 debug_rtx (operands[5]);
1767 fprintf(stderr, "\033[0m");
1768#endif
1769}
1770
1771/* Emit a setcc instruction in its entirity. */
1772
1773static bool
1774mep_expand_setcc_1 (enum rtx_code code, rtx dest, rtx op1, rtx op2)
1775{
1776 rtx tmp;
1777
1778 switch (code)
1779 {
1780 case GT:
1781 case GTU:
1782 tmp = op1, op1 = op2, op2 = tmp;
1783 code = swap_condition (code);
1784 /* FALLTHRU */
1785
1786 case LT:
1787 case LTU:
1788 op1 = force_reg (SImode, op1);
1789 emit_insn (gen_rtx_SET (VOIDmode, dest,
1790 gen_rtx_fmt_ee (code, SImode, op1, op2)));
1791 return true;
1792
1793 case EQ:
1794 if (op2 != const0_rtx)
1795 op1 = expand_binop (SImode, sub_optab, op1, op2, NULL, 1, OPTAB_WIDEN);
1796 mep_expand_setcc_1 (LTU, dest, op1, const1_rtx);
1797 return true;
1798
1799 case NE:
1800 /* Branchful sequence:
1801 mov dest, 0 16-bit
1802 beq op1, op2, Lover 16-bit (op2 < 16), 32-bit otherwise
1803 mov dest, 1 16-bit
1804
1805 Branchless sequence:
1806 add3 tmp, op1, -op2 32-bit (or mov + sub)
1807 sltu3 tmp, tmp, 1 16-bit
1808 xor3 dest, tmp, 1 32-bit
1809 */
1810 if (optimize_size && op2 != const0_rtx)
1811 return false;
1812
1813 if (op2 != const0_rtx)
1814 op1 = expand_binop (SImode, sub_optab, op1, op2, NULL, 1, OPTAB_WIDEN);
1815
1816 op2 = gen_reg_rtx (SImode);
1817 mep_expand_setcc_1 (LTU, op2, op1, const1_rtx);
1818
1819 emit_insn (gen_rtx_SET (VOIDmode, dest,
1820 gen_rtx_XOR (SImode, op2, const1_rtx)));
1821 return true;
1822
1823 case LE:
1824 if (GET_CODE (op2) != CONST_INT
1825 || INTVAL (op2) == 0x7ffffff)
1826 return false;
1827 op2 = GEN_INT (INTVAL (op2) + 1);
1828 return mep_expand_setcc_1 (LT, dest, op1, op2);
1829
1830 case LEU:
1831 if (GET_CODE (op2) != CONST_INT
1832 || INTVAL (op2) == -1)
1833 return false;
1834 op2 = GEN_INT (trunc_int_for_mode (INTVAL (op2) + 1, SImode));
1835 return mep_expand_setcc_1 (LTU, dest, op1, op2);
1836
1837 case GE:
1838 if (GET_CODE (op2) != CONST_INT
1839 || INTVAL (op2) == trunc_int_for_mode (0x80000000, SImode))
1840 return false;
1841 op2 = GEN_INT (INTVAL (op2) - 1);
1842 return mep_expand_setcc_1 (GT, dest, op1, op2);
1843
1844 case GEU:
1845 if (GET_CODE (op2) != CONST_INT
1846 || op2 == const0_rtx)
1847 return false;
1848 op2 = GEN_INT (trunc_int_for_mode (INTVAL (op2) - 1, SImode));
1849 return mep_expand_setcc_1 (GTU, dest, op1, op2);
1850
1851 default:
1852 gcc_unreachable ();
1853 }
1854}
1855
1856bool
1857mep_expand_setcc (rtx *operands)
1858{
1859 rtx dest = operands[0];
1860 enum rtx_code code = GET_CODE (operands[1]);
1861 rtx op0 = operands[2];
1862 rtx op1 = operands[3];
1863
1864 return mep_expand_setcc_1 (code, dest, op0, op1);
1865}
1866
1867rtx
1868mep_expand_cbranch (rtx *operands)
1869{
1870 enum rtx_code code = GET_CODE (operands[0]);
1871 rtx op0 = operands[1];
1872 rtx op1 = operands[2];
1873 rtx tmp;
1874
1875 restart:
1876 switch (code)
1877 {
1878 case LT:
1879 if (mep_imm4_operand (op1, SImode))
1880 break;
1881
1882 tmp = gen_reg_rtx (SImode);
1883 gcc_assert (mep_expand_setcc_1 (LT, tmp, op0, op1));
1884 code = NE;
1885 op0 = tmp;
1886 op1 = const0_rtx;
1887 break;
1888
1889 case GE:
1890 if (mep_imm4_operand (op1, SImode))
1891 break;
1892
1893 tmp = gen_reg_rtx (SImode);
1894 gcc_assert (mep_expand_setcc_1 (LT, tmp, op0, op1));
1895
1896 code = EQ;
1897 op0 = tmp;
1898 op1 = const0_rtx;
1899 break;
1900
1901 case EQ:
1902 case NE:
1903 if (! mep_reg_or_imm4_operand (op1, SImode))
1904 op1 = force_reg (SImode, op1);
1905 break;
1906
1907 case LE:
1908 case GT:
1909 if (GET_CODE (op1) == CONST_INT
1910 && INTVAL (op1) != 0x7fffffff)
1911 {
1912 op1 = GEN_INT (INTVAL (op1) + 1);
1913 code = (code == LE ? LT : GE);
1914 goto restart;
1915 }
1916
1917 tmp = gen_reg_rtx (SImode);
1918 gcc_assert (mep_expand_setcc_1 (LT, tmp, op1, op0));
1919
1920 code = (code == LE ? EQ : NE);
1921 op0 = tmp;
1922 op1 = const0_rtx;
1923 break;
1924
1925 case LTU:
1926 if (op1 == const1_rtx)
1927 {
1928 code = EQ;
1929 op1 = const0_rtx;
1930 break;
1931 }
1932
1933 tmp = gen_reg_rtx (SImode);
1934 gcc_assert (mep_expand_setcc_1 (LTU, tmp, op0, op1));
1935 code = NE;
1936 op0 = tmp;
1937 op1 = const0_rtx;
1938 break;
1939
1940 case LEU:
1941 tmp = gen_reg_rtx (SImode);
1942 if (mep_expand_setcc_1 (LEU, tmp, op0, op1))
1943 code = NE;
1944 else if (mep_expand_setcc_1 (LTU, tmp, op1, op0))
1945 code = EQ;
1946 else
1947 gcc_unreachable ();
1948 op0 = tmp;
1949 op1 = const0_rtx;
1950 break;
1951
1952 case GTU:
1953 tmp = gen_reg_rtx (SImode);
1954 gcc_assert (mep_expand_setcc_1 (GTU, tmp, op0, op1)
1955 || mep_expand_setcc_1 (LTU, tmp, op1, op0));
1956 code = NE;
1957 op0 = tmp;
1958 op1 = const0_rtx;
1959 break;
1960
1961 case GEU:
1962 tmp = gen_reg_rtx (SImode);
1963 if (mep_expand_setcc_1 (GEU, tmp, op0, op1))
1964 code = NE;
1965 else if (mep_expand_setcc_1 (LTU, tmp, op0, op1))
1966 code = EQ;
1967 else
1968 gcc_unreachable ();
1969 op0 = tmp;
1970 op1 = const0_rtx;
1971 break;
1972
1973 default:
1974 gcc_unreachable ();
1975 }
1976
1977 return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
1978}
1979
1980const char *
1981mep_emit_cbranch (rtx *operands, int ne)
1982{
1983 if (GET_CODE (operands[1]) == REG)
1984 return ne ? "bne\t%0, %1, %l2" : "beq\t%0, %1, %l2";
1985 else if (INTVAL (operands[1]) == 0)
1986 return ne ? "bnez\t%0, %l2" : "beqz\t%0, %l2";
1987 else
1988 return ne ? "bnei\t%0, %1, %l2" : "beqi\t%0, %1, %l2";
1989}
1990
1991void
1992mep_expand_call (rtx *operands, int returns_value)
1993{
1994 rtx addr = operands[returns_value];
1995 rtx tp = mep_tp_rtx ();
1996 rtx gp = mep_gp_rtx ();
1997
1998 gcc_assert (GET_CODE (addr) == MEM);
1999
2000 addr = XEXP (addr, 0);
2001
2002 if (! mep_call_address_operand (addr, VOIDmode))
2003 addr = force_reg (SImode, addr);
2004
2005 if (! operands[returns_value+2])
2006 operands[returns_value+2] = const0_rtx;
2007
2008 if (returns_value)
2009 emit_call_insn (gen_call_value_internal (operands[0], addr, operands[2],
2010 operands[3], tp, gp));
2011 else
2012 emit_call_insn (gen_call_internal (addr, operands[1],
2013 operands[2], tp, gp));
2014}
2015\f
2016/* Aliasing Support. */
2017
2018/* If X is a machine specific address (i.e. a symbol or label being
2019 referenced as a displacement from the GOT implemented using an
2020 UNSPEC), then return the base term. Otherwise return X. */
2021
2022rtx
2023mep_find_base_term (rtx x)
2024{
2025 rtx base, term;
2026 int unspec;
2027
2028 if (GET_CODE (x) != PLUS)
2029 return x;
2030 base = XEXP (x, 0);
2031 term = XEXP (x, 1);
2032
2033 if (has_hard_reg_initial_val(Pmode, TP_REGNO)
2034 && base == mep_tp_rtx ())
2035 unspec = UNS_TPREL;
2036 else if (has_hard_reg_initial_val(Pmode, GP_REGNO)
2037 && base == mep_gp_rtx ())
2038 unspec = UNS_GPREL;
2039 else
2040 return x;
2041
2042 if (GET_CODE (term) != CONST)
2043 return x;
2044 term = XEXP (term, 0);
2045
2046 if (GET_CODE (term) != UNSPEC
2047 || XINT (term, 1) != unspec)
2048 return x;
2049
2050 return XVECEXP (term, 0, 0);
2051}
2052\f
2053/* Reload Support. */
2054
2055/* Return true if the registers in CLASS cannot represent the change from
2056 modes FROM to TO. */
2057
2058bool
2059mep_cannot_change_mode_class (enum machine_mode from, enum machine_mode to,
2060 enum reg_class regclass)
2061{
2062 if (from == to)
2063 return false;
2064
2065 /* 64-bit COP regs must remain 64-bit COP regs. */
2066 if (TARGET_64BIT_CR_REGS
2067 && (regclass == CR_REGS
2068 || regclass == LOADABLE_CR_REGS)
2069 && (GET_MODE_SIZE (to) < 8
2070 || GET_MODE_SIZE (from) < 8))
2071 return true;
2072
2073 return false;
2074}
2075
2076#define MEP_NONGENERAL_CLASS(C) (!reg_class_subset_p (C, GENERAL_REGS))
2077
2078static bool
2079mep_general_reg (rtx x)
2080{
2081 while (GET_CODE (x) == SUBREG)
2082 x = XEXP (x, 0);
2083 return GET_CODE (x) == REG && GR_REGNO_P (REGNO (x));
2084}
2085
2086static bool
2087mep_nongeneral_reg (rtx x)
2088{
2089 while (GET_CODE (x) == SUBREG)
2090 x = XEXP (x, 0);
2091 return (GET_CODE (x) == REG
2092 && !GR_REGNO_P (REGNO (x)) && REGNO (x) < FIRST_PSEUDO_REGISTER);
2093}
2094
2095static bool
2096mep_general_copro_reg (rtx x)
2097{
2098 while (GET_CODE (x) == SUBREG)
2099 x = XEXP (x, 0);
2100 return (GET_CODE (x) == REG && CR_REGNO_P (REGNO (x)));
2101}
2102
2103static bool
2104mep_nonregister (rtx x)
2105{
2106 while (GET_CODE (x) == SUBREG)
2107 x = XEXP (x, 0);
2108 return (GET_CODE (x) != REG || REGNO (x) >= FIRST_PSEUDO_REGISTER);
2109}
2110
2111#define DEBUG_RELOAD 0
2112
2113/* Return the secondary reload class needed for moving value X to or
2114 from a register in coprocessor register class CLASS. */
2115
2116static enum reg_class
2117mep_secondary_copro_reload_class (enum reg_class rclass, rtx x)
2118{
2119 if (mep_general_reg (x))
2120 /* We can do the move directly if mep_have_core_copro_moves_p,
2121 otherwise we need to go through memory. Either way, no secondary
2122 register is needed. */
2123 return NO_REGS;
2124
2125 if (mep_general_copro_reg (x))
2126 {
2127 /* We can do the move directly if mep_have_copro_copro_moves_p. */
2128 if (mep_have_copro_copro_moves_p)
2129 return NO_REGS;
2130
2131 /* Otherwise we can use a temporary if mep_have_core_copro_moves_p. */
2132 if (mep_have_core_copro_moves_p)
2133 return GENERAL_REGS;
2134
2135 /* Otherwise we need to do it through memory. No secondary
2136 register is needed. */
2137 return NO_REGS;
2138 }
2139
2140 if (reg_class_subset_p (rclass, LOADABLE_CR_REGS)
2141 && constraint_satisfied_p (x, CONSTRAINT_U))
2142 /* X is a memory value that we can access directly. */
2143 return NO_REGS;
2144
2145 /* We have to move X into a GPR first and then copy it to
2146 the coprocessor register. The move from the GPR to the
2147 coprocessor might be done directly or through memory,
2148 depending on mep_have_core_copro_moves_p. */
2149 return GENERAL_REGS;
2150}
2151
2152/* Copying X to register in RCLASS. */
2153
2154int
2155mep_secondary_input_reload_class (enum reg_class rclass,
2156 enum machine_mode mode ATTRIBUTE_UNUSED,
2157 rtx x)
2158{
2159 int rv = NO_REGS;
2160
2161#if DEBUG_RELOAD
2162 fprintf (stderr, "secondary input reload copy to %s %s from ", reg_class_names[rclass], mode_name[mode]);
2163 debug_rtx (x);
2164#endif
2165
2166 if (reg_class_subset_p (rclass, CR_REGS))
2167 rv = mep_secondary_copro_reload_class (rclass, x);
2168 else if (MEP_NONGENERAL_CLASS (rclass)
2169 && (mep_nonregister (x) || mep_nongeneral_reg (x)))
2170 rv = GENERAL_REGS;
2171
2172#if DEBUG_RELOAD
2173 fprintf (stderr, " - requires %s\n", reg_class_names[rv]);
2174#endif
2175 return rv;
2176}
2177
2178/* Copying register in RCLASS to X. */
2179
2180int
2181mep_secondary_output_reload_class (enum reg_class rclass,
2182 enum machine_mode mode ATTRIBUTE_UNUSED,
2183 rtx x)
2184{
2185 int rv = NO_REGS;
2186
2187#if DEBUG_RELOAD
2188 fprintf (stderr, "secondary output reload copy from %s %s to ", reg_class_names[rclass], mode_name[mode]);
2189 debug_rtx (x);
2190#endif
2191
2192 if (reg_class_subset_p (rclass, CR_REGS))
2193 rv = mep_secondary_copro_reload_class (rclass, x);
2194 else if (MEP_NONGENERAL_CLASS (rclass)
2195 && (mep_nonregister (x) || mep_nongeneral_reg (x)))
2196 rv = GENERAL_REGS;
2197
2198#if DEBUG_RELOAD
2199 fprintf (stderr, " - requires %s\n", reg_class_names[rv]);
2200#endif
2201
2202 return rv;
2203}
2204
2205/* Implement SECONDARY_MEMORY_NEEDED. */
2206
2207bool
2208mep_secondary_memory_needed (enum reg_class rclass1, enum reg_class rclass2,
2209 enum machine_mode mode ATTRIBUTE_UNUSED)
2210{
2211 if (!mep_have_core_copro_moves_p)
2212 {
2213 if (reg_classes_intersect_p (rclass1, CR_REGS)
2214 && reg_classes_intersect_p (rclass2, GENERAL_REGS))
2215 return true;
2216 if (reg_classes_intersect_p (rclass2, CR_REGS)
2217 && reg_classes_intersect_p (rclass1, GENERAL_REGS))
2218 return true;
2219 if (!mep_have_copro_copro_moves_p
2220 && reg_classes_intersect_p (rclass1, CR_REGS)
2221 && reg_classes_intersect_p (rclass2, CR_REGS))
2222 return true;
2223 }
2224 return false;
2225}
2226
2227void
2228mep_expand_reload (rtx *operands, enum machine_mode mode)
2229{
2230 /* There are three cases for each direction:
2231 register, farsym
2232 control, farsym
2233 control, nearsym */
2234
2235 int s0 = mep_section_tag (operands[0]) == 'f';
2236 int s1 = mep_section_tag (operands[1]) == 'f';
2237 int c0 = mep_nongeneral_reg (operands[0]);
2238 int c1 = mep_nongeneral_reg (operands[1]);
2239 int which = (s0 ? 20:0) + (c0 ? 10:0) + (s1 ? 2:0) + (c1 ? 1:0);
2240
2241#if DEBUG_RELOAD
2242 fprintf (stderr, "expand_reload %s\n", mode_name[mode]);
2243 debug_rtx (operands[0]);
2244 debug_rtx (operands[1]);
2245#endif
2246
2247 switch (which)
2248 {
2249 case 00: /* Don't know why this gets here. */
2250 case 02: /* general = far */
2251 emit_move_insn (operands[0], operands[1]);
2252 return;
2253
2254 case 10: /* cr = mem */
2255 case 11: /* cr = cr */
2256 case 01: /* mem = cr */
2257 case 12: /* cr = far */
2258 emit_move_insn (operands[2], operands[1]);
2259 emit_move_insn (operands[0], operands[2]);
2260 return;
2261
2262 case 20: /* far = general */
2263 emit_move_insn (operands[2], XEXP (operands[1], 0));
2264 emit_move_insn (operands[0], gen_rtx_MEM (mode, operands[2]));
2265 return;
2266
2267 case 21: /* far = cr */
2268 case 22: /* far = far */
2269 default:
2270 fprintf (stderr, "unsupported expand reload case %02d for mode %s\n",
2271 which, mode_name[mode]);
2272 debug_rtx (operands[0]);
2273 debug_rtx (operands[1]);
2274 gcc_unreachable ();
2275 }
2276}
2277
2278/* Implement PREFERRED_RELOAD_CLASS. See whether X is a constant that
2279 can be moved directly into registers 0 to 7, but not into the rest.
2280 If so, and if the required class includes registers 0 to 7, restrict
2281 it to those registers. */
2282
2283enum reg_class
2284mep_preferred_reload_class (rtx x, enum reg_class rclass)
2285{
2286 switch (GET_CODE (x))
2287 {
2288 case CONST_INT:
2289 if (INTVAL (x) >= 0x10000
2290 && INTVAL (x) < 0x01000000
2291 && (INTVAL (x) & 0xffff) != 0
2292 && reg_class_subset_p (TPREL_REGS, rclass))
2293 rclass = TPREL_REGS;
2294 break;
2295
2296 case CONST:
2297 case SYMBOL_REF:
2298 case LABEL_REF:
2299 if (mep_section_tag (x) != 'f'
2300 && reg_class_subset_p (TPREL_REGS, rclass))
2301 rclass = TPREL_REGS;
2302 break;
2303
2304 default:
2305 break;
2306 }
2307 return rclass;
2308}
2309\f
2310/* Implement REGISTER_MOVE_COST. Return 2 for direct single-register
2311 moves, 4 for direct double-register moves, and 1000 for anything
2312 that requires a temporary register or temporary stack slot. */
2313
2314int
2315mep_register_move_cost (enum machine_mode mode, enum reg_class from, enum reg_class to)
2316{
2317 if (mep_have_copro_copro_moves_p
2318 && reg_class_subset_p (from, CR_REGS)
2319 && reg_class_subset_p (to, CR_REGS))
2320 {
2321 if (TARGET_32BIT_CR_REGS && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
2322 return 4;
2323 return 2;
2324 }
2325 if (reg_class_subset_p (from, CR_REGS)
2326 && reg_class_subset_p (to, CR_REGS))
2327 {
2328 if (TARGET_32BIT_CR_REGS && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
2329 return 8;
2330 return 4;
2331 }
2332 if (reg_class_subset_p (from, CR_REGS)
2333 || reg_class_subset_p (to, CR_REGS))
2334 {
2335 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
2336 return 4;
2337 return 2;
2338 }
2339 if (mep_secondary_memory_needed (from, to, mode))
2340 return 1000;
2341 if (MEP_NONGENERAL_CLASS (from) && MEP_NONGENERAL_CLASS (to))
2342 return 1000;
2343
2344 if (GET_MODE_SIZE (mode) > 4)
2345 return 4;
2346
2347 return 2;
2348}
2349
2350\f
2351/* Functions to save and restore machine-specific function data. */
2352
2353static struct machine_function *
2354mep_init_machine_status (void)
2355{
2356 struct machine_function *f;
2357
2358 f = (struct machine_function *) ggc_alloc_cleared (sizeof (struct machine_function));
2359
2360 return f;
2361}
2362
2363static rtx
2364mep_allocate_initial_value (rtx reg)
2365{
2366 int rss;
2367
2368 if (GET_CODE (reg) != REG)
2369 return NULL_RTX;
2370
2371 if (REGNO (reg) >= FIRST_PSEUDO_REGISTER)
2372 return NULL_RTX;
2373
2374 /* In interrupt functions, the "initial" values of $gp and $tp are
2375 provided by the prologue. They are not necessarily the same as
2376 the values that the caller was using. */
2377 if (REGNO (reg) == TP_REGNO || REGNO (reg) == GP_REGNO)
2378 if (mep_interrupt_p ())
2379 return NULL_RTX;
2380
2381 if (! cfun->machine->reg_save_slot[REGNO(reg)])
2382 {
2383 cfun->machine->reg_save_size += 4;
2384 cfun->machine->reg_save_slot[REGNO(reg)] = cfun->machine->reg_save_size;
2385 }
2386
2387 rss = cfun->machine->reg_save_slot[REGNO(reg)];
2388 return gen_rtx_MEM (SImode, plus_constant (arg_pointer_rtx, -rss));
2389}
2390
2391rtx
2392mep_return_addr_rtx (int count)
2393{
2394 if (count != 0)
2395 return const0_rtx;
2396
2397 return get_hard_reg_initial_val (Pmode, LP_REGNO);
2398}
2399
2400static rtx
2401mep_tp_rtx (void)
2402{
2403 return get_hard_reg_initial_val (Pmode, TP_REGNO);
2404}
2405
2406static rtx
2407mep_gp_rtx (void)
2408{
2409 return get_hard_reg_initial_val (Pmode, GP_REGNO);
2410}
2411
2412static bool
2413mep_interrupt_p (void)
2414{
2415 if (cfun->machine->interrupt_handler == 0)
2416 {
2417 int interrupt_handler
2418 = (lookup_attribute ("interrupt",
2419 DECL_ATTRIBUTES (current_function_decl))
2420 != NULL_TREE);
2421 cfun->machine->interrupt_handler = interrupt_handler ? 2 : 1;
2422 }
2423 return cfun->machine->interrupt_handler == 2;
2424}
2425
2426static bool
2427mep_disinterrupt_p (void)
2428{
2429 if (cfun->machine->disable_interrupts == 0)
2430 {
2431 int disable_interrupts
2432 = (lookup_attribute ("disinterrupt",
2433 DECL_ATTRIBUTES (current_function_decl))
2434 != NULL_TREE);
2435 cfun->machine->disable_interrupts = disable_interrupts ? 2 : 1;
2436 }
2437 return cfun->machine->disable_interrupts == 2;
2438}
2439
2440\f
2441/* Frame/Epilog/Prolog Related. */
2442
2443static bool
2444mep_reg_set_p (rtx reg, rtx insn)
2445{
2446 /* Similar to reg_set_p in rtlanal.c, but we ignore calls */
2447 if (INSN_P (insn))
2448 {
2449 if (FIND_REG_INC_NOTE (insn, reg))
2450 return true;
2451 insn = PATTERN (insn);
2452 }
2453
2454 if (GET_CODE (insn) == SET
2455 && GET_CODE (XEXP (insn, 0)) == REG
2456 && GET_CODE (XEXP (insn, 1)) == REG
2457 && REGNO (XEXP (insn, 0)) == REGNO (XEXP (insn, 1)))
2458 return false;
2459
2460 return set_of (reg, insn) != NULL_RTX;
2461}
2462
2463
2464#define MEP_SAVES_UNKNOWN 0
2465#define MEP_SAVES_YES 1
2466#define MEP_SAVES_MAYBE 2
2467#define MEP_SAVES_NO 3
2468
2469static bool
2470mep_reg_set_in_function (int regno)
2471{
2472 rtx reg, insn;
2473
2474 if (mep_interrupt_p () && df_regs_ever_live_p(regno))
2475 return true;
2476
2477 if (regno == LP_REGNO && (profile_arc_flag > 0 || profile_flag > 0))
2478 return true;
2479
2480 push_topmost_sequence ();
2481 insn = get_insns ();
2482 pop_topmost_sequence ();
2483
2484 if (!insn)
2485 return false;
2486
2487 reg = gen_rtx_REG (SImode, regno);
2488
2489 for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
2490 if (INSN_P (insn) && mep_reg_set_p (reg, insn))
2491 return true;
2492 return false;
2493}
2494
2495static bool
2496mep_asm_without_operands_p (void)
2497{
2498 if (cfun->machine->asms_without_operands == 0)
2499 {
2500 rtx insn;
2501
2502 push_topmost_sequence ();
2503 insn = get_insns ();
2504 pop_topmost_sequence ();
2505
2506 cfun->machine->asms_without_operands = 1;
2507 while (insn)
2508 {
2509 if (INSN_P (insn)
2510 && GET_CODE (PATTERN (insn)) == ASM_INPUT)
2511 {
2512 cfun->machine->asms_without_operands = 2;
2513 break;
2514 }
2515 insn = NEXT_INSN (insn);
2516 }
2517
2518 }
2519 return cfun->machine->asms_without_operands == 2;
2520}
2521
2522/* Interrupt functions save/restore every call-preserved register, and
2523 any call-used register it uses (or all if it calls any function,
2524 since they may get clobbered there too). Here we check to see
2525 which call-used registers need saving. */
2526
d1b5afd5
DD
2527#define IVC2_ISAVED_REG(r) (TARGET_IVC2 \
2528 && (r == FIRST_CCR_REGNO + 1 \
2529 || (r >= FIRST_CCR_REGNO + 8 && r <= FIRST_CCR_REGNO + 11) \
2530 || (r >= FIRST_CCR_REGNO + 16 && r <= FIRST_CCR_REGNO + 31)))
2531
7acf4da6
DD
2532static bool
2533mep_interrupt_saved_reg (int r)
2534{
2535 if (!mep_interrupt_p ())
2536 return false;
2537 if (r == REGSAVE_CONTROL_TEMP
2538 || (TARGET_64BIT_CR_REGS && TARGET_COP && r == REGSAVE_CONTROL_TEMP+1))
2539 return true;
2540 if (mep_asm_without_operands_p ()
2541 && (!fixed_regs[r]
d1b5afd5
DD
2542 || (r == RPB_REGNO || r == RPE_REGNO || r == RPC_REGNO || r == LP_REGNO)
2543 || IVC2_ISAVED_REG (r)))
7acf4da6
DD
2544 return true;
2545 if (!current_function_is_leaf)
2546 /* Function calls mean we need to save $lp. */
d1b5afd5 2547 if (r == LP_REGNO || IVC2_ISAVED_REG (r))
7acf4da6
DD
2548 return true;
2549 if (!current_function_is_leaf || cfun->machine->doloop_tags > 0)
2550 /* The interrupt handler might use these registers for repeat blocks,
2551 or it might call a function that does so. */
2552 if (r == RPB_REGNO || r == RPE_REGNO || r == RPC_REGNO)
2553 return true;
2554 if (current_function_is_leaf && call_used_regs[r] && !df_regs_ever_live_p(r))
2555 return false;
2556 /* Functions we call might clobber these. */
2557 if (call_used_regs[r] && !fixed_regs[r])
2558 return true;
f2082f90 2559 /* Additional registers that need to be saved for IVC2. */
d1b5afd5 2560 if (IVC2_ISAVED_REG (r))
f2082f90
DD
2561 return true;
2562
7acf4da6
DD
2563 return false;
2564}
2565
2566static bool
2567mep_call_saves_register (int r)
2568{
e756464b 2569 if (! cfun->machine->frame_locked)
7acf4da6
DD
2570 {
2571 int rv = MEP_SAVES_NO;
2572
2573 if (cfun->machine->reg_save_slot[r])
2574 rv = MEP_SAVES_YES;
2575 else if (r == LP_REGNO && (profile_arc_flag > 0 || profile_flag > 0))
2576 rv = MEP_SAVES_YES;
2577 else if (r == FRAME_POINTER_REGNUM && frame_pointer_needed)
2578 rv = MEP_SAVES_YES;
2579 else if ((!call_used_regs[r] || r == LP_REGNO) && df_regs_ever_live_p(r))
2580 rv = MEP_SAVES_YES;
2581 else if (crtl->calls_eh_return && (r == 10 || r == 11))
2582 /* We need these to have stack slots so that they can be set during
2583 unwinding. */
2584 rv = MEP_SAVES_YES;
2585 else if (mep_interrupt_saved_reg (r))
2586 rv = MEP_SAVES_YES;
2587 cfun->machine->reg_saved[r] = rv;
2588 }
2589 return cfun->machine->reg_saved[r] == MEP_SAVES_YES;
2590}
2591
2592/* Return true if epilogue uses register REGNO. */
2593
2594bool
2595mep_epilogue_uses (int regno)
2596{
2597 /* Since $lp is a call-saved register, the generic code will normally
2598 mark it used in the epilogue if it needs to be saved and restored.
2599 However, when profiling is enabled, the profiling code will implicitly
2600 clobber $11. This case has to be handled specially both here and in
2601 mep_call_saves_register. */
2602 if (regno == LP_REGNO && (profile_arc_flag > 0 || profile_flag > 0))
2603 return true;
2604 /* Interrupt functions save/restore pretty much everything. */
2605 return (reload_completed && mep_interrupt_saved_reg (regno));
2606}
2607
2608static int
2609mep_reg_size (int regno)
2610{
2611 if (CR_REGNO_P (regno) && TARGET_64BIT_CR_REGS)
2612 return 8;
2613 return 4;
2614}
2615
7b5cbb57
AS
2616/* Worker function for TARGET_CAN_ELIMINATE. */
2617
2618bool
2619mep_can_eliminate (const int from, const int to)
2620{
2621 return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM
2622 ? ! frame_pointer_needed
2623 : true);
2624}
2625
7acf4da6
DD
2626int
2627mep_elimination_offset (int from, int to)
2628{
2629 int reg_save_size;
2630 int i;
2631 int frame_size = get_frame_size () + crtl->outgoing_args_size;
2632 int total_size;
2633
e756464b
DD
2634 if (!cfun->machine->frame_locked)
2635 memset (cfun->machine->reg_saved, 0, sizeof (cfun->machine->reg_saved));
7acf4da6
DD
2636
2637 /* We don't count arg_regs_to_save in the arg pointer offset, because
2638 gcc thinks the arg pointer has moved along with the saved regs.
2639 However, we do count it when we adjust $sp in the prologue. */
2640 reg_save_size = 0;
2641 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2642 if (mep_call_saves_register (i))
2643 reg_save_size += mep_reg_size (i);
2644
2645 if (reg_save_size % 8)
2646 cfun->machine->regsave_filler = 8 - (reg_save_size % 8);
2647 else
2648 cfun->machine->regsave_filler = 0;
2649
2650 /* This is what our total stack adjustment looks like. */
2651 total_size = (reg_save_size + frame_size + cfun->machine->regsave_filler);
2652
2653 if (total_size % 8)
2654 cfun->machine->frame_filler = 8 - (total_size % 8);
2655 else
2656 cfun->machine->frame_filler = 0;
2657
2658
2659 if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
2660 return reg_save_size + cfun->machine->regsave_filler;
2661
2662 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
2663 return cfun->machine->frame_filler + frame_size;
2664
2665 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
2666 return reg_save_size + cfun->machine->regsave_filler + cfun->machine->frame_filler + frame_size;
2667
2668 gcc_unreachable ();
2669}
2670
2671static rtx
2672F (rtx x)
2673{
2674 RTX_FRAME_RELATED_P (x) = 1;
2675 return x;
2676}
2677
2678/* Since the prologue/epilogue code is generated after optimization,
2679 we can't rely on gcc to split constants for us. So, this code
2680 captures all the ways to add a constant to a register in one logic
2681 chunk, including optimizing away insns we just don't need. This
2682 makes the prolog/epilog code easier to follow. */
2683static void
2684add_constant (int dest, int src, int value, int mark_frame)
2685{
2686 rtx insn;
2687 int hi, lo;
2688
2689 if (src == dest && value == 0)
2690 return;
2691
2692 if (value == 0)
2693 {
2694 insn = emit_move_insn (gen_rtx_REG (SImode, dest),
2695 gen_rtx_REG (SImode, src));
2696 if (mark_frame)
2697 RTX_FRAME_RELATED_P(insn) = 1;
2698 return;
2699 }
2700
2701 if (value >= -32768 && value <= 32767)
2702 {
2703 insn = emit_insn (gen_addsi3 (gen_rtx_REG (SImode, dest),
2704 gen_rtx_REG (SImode, src),
2705 GEN_INT (value)));
2706 if (mark_frame)
2707 RTX_FRAME_RELATED_P(insn) = 1;
2708 return;
2709 }
2710
2711 /* Big constant, need to use a temp register. We use
2712 REGSAVE_CONTROL_TEMP because it's call clobberable (the reg save
2713 area is always small enough to directly add to). */
2714
2715 hi = trunc_int_for_mode (value & 0xffff0000, SImode);
2716 lo = value & 0xffff;
2717
2718 insn = emit_move_insn (gen_rtx_REG (SImode, REGSAVE_CONTROL_TEMP),
2719 GEN_INT (hi));
2720
2721 if (lo)
2722 {
2723 insn = emit_insn (gen_iorsi3 (gen_rtx_REG (SImode, REGSAVE_CONTROL_TEMP),
2724 gen_rtx_REG (SImode, REGSAVE_CONTROL_TEMP),
2725 GEN_INT (lo)));
2726 }
2727
2728 insn = emit_insn (gen_addsi3 (gen_rtx_REG (SImode, dest),
2729 gen_rtx_REG (SImode, src),
2730 gen_rtx_REG (SImode, REGSAVE_CONTROL_TEMP)));
2731 if (mark_frame)
2732 {
2733 RTX_FRAME_RELATED_P(insn) = 1;
2734 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
2735 gen_rtx_SET (SImode,
2736 gen_rtx_REG (SImode, dest),
2737 gen_rtx_PLUS (SImode,
2738 gen_rtx_REG (SImode, dest),
2739 GEN_INT (value))));
2740 }
2741}
2742
2743static bool
2744mep_function_uses_sp (void)
2745{
2746 rtx insn;
2747 struct sequence_stack *seq;
2748 rtx sp = gen_rtx_REG (SImode, SP_REGNO);
2749
2750 insn = get_insns ();
2751 for (seq = crtl->emit.sequence_stack;
2752 seq;
2753 insn = seq->first, seq = seq->next);
2754
2755 while (insn)
2756 {
2757 if (mep_mentioned_p (insn, sp, 0))
2758 return true;
2759 insn = NEXT_INSN (insn);
2760 }
2761 return false;
2762}
2763
2764/* Move SRC to DEST. Mark the move as being potentially dead if
2765 MAYBE_DEAD_P. */
2766
2767static rtx
2768maybe_dead_move (rtx dest, rtx src, bool ATTRIBUTE_UNUSED maybe_dead_p)
2769{
2770 rtx insn = emit_move_insn (dest, src);
2771#if 0
2772 if (maybe_dead_p)
2773 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL);
2774#endif
2775 return insn;
2776}
2777
2778/* Used for interrupt functions, which can't assume that $tp and $gp
2779 contain the correct pointers. */
2780
2781static void
2782mep_reload_pointer (int regno, const char *symbol)
2783{
2784 rtx reg, sym;
2785
2786 if (!df_regs_ever_live_p(regno) && current_function_is_leaf)
2787 return;
2788
2789 reg = gen_rtx_REG (SImode, regno);
2790 sym = gen_rtx_SYMBOL_REF (SImode, symbol);
2791 emit_insn (gen_movsi_topsym_s (reg, sym));
2792 emit_insn (gen_movsi_botsym_s (reg, reg, sym));
2793}
2794
e756464b
DD
2795/* Assign save slots for any register not already saved. DImode
2796 registers go at the end of the reg save area; the rest go at the
2797 beginning. This is for alignment purposes. Returns true if a frame
2798 is really needed. */
2799static bool
2800mep_assign_save_slots (int reg_save_size)
7acf4da6 2801{
e756464b 2802 bool really_need_stack_frame = false;
7acf4da6 2803 int di_ofs = 0;
e756464b 2804 int i;
7acf4da6 2805
7acf4da6
DD
2806 for (i=0; i<FIRST_PSEUDO_REGISTER; i++)
2807 if (mep_call_saves_register(i))
2808 {
2809 int regsize = mep_reg_size (i);
2810
2811 if ((i != TP_REGNO && i != GP_REGNO && i != LP_REGNO)
2812 || mep_reg_set_in_function (i))
e756464b 2813 really_need_stack_frame = true;
7acf4da6
DD
2814
2815 if (cfun->machine->reg_save_slot[i])
2816 continue;
2817
2818 if (regsize < 8)
2819 {
2820 cfun->machine->reg_save_size += regsize;
2821 cfun->machine->reg_save_slot[i] = cfun->machine->reg_save_size;
2822 }
2823 else
2824 {
2825 cfun->machine->reg_save_slot[i] = reg_save_size - di_ofs;
2826 di_ofs += 8;
2827 }
2828 }
e756464b
DD
2829 cfun->machine->frame_locked = 1;
2830 return really_need_stack_frame;
2831}
2832
2833void
2834mep_expand_prologue (void)
2835{
2836 int i, rss, sp_offset = 0;
2837 int reg_save_size;
2838 int frame_size;
2839 int really_need_stack_frame = frame_size;
2840
2841 /* We must not allow register renaming in interrupt functions,
2842 because that invalidates the correctness of the set of call-used
2843 registers we're going to save/restore. */
2844 mep_set_leaf_registers (mep_interrupt_p () ? 0 : 1);
2845
2846 if (mep_disinterrupt_p ())
2847 emit_insn (gen_mep_disable_int ());
2848
2849 cfun->machine->mep_frame_pointer_needed = frame_pointer_needed;
2850
2851 reg_save_size = mep_elimination_offset (ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM);
2852 frame_size = mep_elimination_offset (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM);
2853
2854 really_need_stack_frame |= mep_assign_save_slots (reg_save_size);
7acf4da6
DD
2855
2856 sp_offset = reg_save_size;
2857 if (sp_offset + frame_size < 128)
2858 sp_offset += frame_size ;
2859
2860 add_constant (SP_REGNO, SP_REGNO, -sp_offset, 1);
2861
2862 for (i=0; i<FIRST_PSEUDO_REGISTER; i++)
2863 if (mep_call_saves_register(i))
2864 {
2865 rtx mem;
2866 bool maybe_dead_p;
2867 enum machine_mode rmode;
2868
2869 rss = cfun->machine->reg_save_slot[i];
2870
2871 if ((i == TP_REGNO || i == GP_REGNO || i == LP_REGNO)
2872 && (!mep_reg_set_in_function (i)
2873 && !mep_interrupt_p ()))
2874 continue;
2875
2876 if (mep_reg_size (i) == 8)
2877 rmode = DImode;
2878 else
2879 rmode = SImode;
2880
2881 /* If there is a pseudo associated with this register's initial value,
2882 reload might have already spilt it to the stack slot suggested by
2883 ALLOCATE_INITIAL_VALUE. The moves emitted here can then be safely
2884 deleted as dead. */
2885 mem = gen_rtx_MEM (rmode,
2886 plus_constant (stack_pointer_rtx, sp_offset - rss));
2887 maybe_dead_p = rtx_equal_p (mem, has_hard_reg_initial_val (rmode, i));
2888
2889 if (GR_REGNO_P (i) || LOADABLE_CR_REGNO_P (i))
2890 F(maybe_dead_move (mem, gen_rtx_REG (rmode, i), maybe_dead_p));
2891 else if (rmode == DImode)
2892 {
2893 rtx insn;
2894 int be = TARGET_BIG_ENDIAN ? 4 : 0;
2895
2896 mem = gen_rtx_MEM (SImode,
2897 plus_constant (stack_pointer_rtx, sp_offset - rss + be));
2898
2899 maybe_dead_move (gen_rtx_REG (SImode, REGSAVE_CONTROL_TEMP),
2900 gen_rtx_REG (SImode, i),
2901 maybe_dead_p);
2902 maybe_dead_move (gen_rtx_REG (SImode, REGSAVE_CONTROL_TEMP+1),
2903 gen_rtx_ZERO_EXTRACT (SImode,
2904 gen_rtx_REG (DImode, i),
2905 GEN_INT (32),
2906 GEN_INT (32)),
2907 maybe_dead_p);
2908 insn = maybe_dead_move (mem,
2909 gen_rtx_REG (SImode, REGSAVE_CONTROL_TEMP),
2910 maybe_dead_p);
2911 RTX_FRAME_RELATED_P (insn) = 1;
2912
2913 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
2914 gen_rtx_SET (VOIDmode,
2915 copy_rtx (mem),
2916 gen_rtx_REG (rmode, i)));
2917 mem = gen_rtx_MEM (SImode,
2918 plus_constant (stack_pointer_rtx, sp_offset - rss + (4-be)));
2919 insn = maybe_dead_move (mem,
2920 gen_rtx_REG (SImode, REGSAVE_CONTROL_TEMP+1),
2921 maybe_dead_p);
2922 }
2923 else
2924 {
2925 rtx insn;
2926 maybe_dead_move (gen_rtx_REG (rmode, REGSAVE_CONTROL_TEMP),
2927 gen_rtx_REG (rmode, i),
2928 maybe_dead_p);
2929 insn = maybe_dead_move (mem,
2930 gen_rtx_REG (rmode, REGSAVE_CONTROL_TEMP),
2931 maybe_dead_p);
2932 RTX_FRAME_RELATED_P (insn) = 1;
2933
2934 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
2935 gen_rtx_SET (VOIDmode,
2936 copy_rtx (mem),
2937 gen_rtx_REG (rmode, i)));
2938 }
2939 }
2940
2941 if (frame_pointer_needed)
a46f0964
DD
2942 {
2943 /* We've already adjusted down by sp_offset. Total $sp change
2944 is reg_save_size + frame_size. We want a net change here of
2945 just reg_save_size. */
2946 add_constant (FP_REGNO, SP_REGNO, sp_offset - reg_save_size, 1);
2947 }
7acf4da6
DD
2948
2949 add_constant (SP_REGNO, SP_REGNO, sp_offset-(reg_save_size+frame_size), 1);
2950
2951 if (mep_interrupt_p ())
2952 {
2953 mep_reload_pointer(GP_REGNO, "__sdabase");
2954 mep_reload_pointer(TP_REGNO, "__tpbase");
2955 }
2956}
2957
2958static void
2959mep_start_function (FILE *file, HOST_WIDE_INT hwi_local)
2960{
2961 int local = hwi_local;
2962 int frame_size = local + crtl->outgoing_args_size;
2963 int reg_save_size;
2964 int ffill;
2965 int i, sp, skip;
2966 int sp_offset;
2967 int slot_map[FIRST_PSEUDO_REGISTER], si, sj;
2968
2969 reg_save_size = mep_elimination_offset (ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM);
2970 frame_size = mep_elimination_offset (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM);
2971 sp_offset = reg_save_size + frame_size;
2972
2973 ffill = cfun->machine->frame_filler;
2974
2975 if (cfun->machine->mep_frame_pointer_needed)
2976 reg_names[FP_REGNO] = "$fp";
2977 else
2978 reg_names[FP_REGNO] = "$8";
2979
2980 if (sp_offset == 0)
2981 return;
2982
2983 if (debug_info_level == DINFO_LEVEL_NONE)
2984 {
2985 fprintf (file, "\t# frame: %d", sp_offset);
2986 if (reg_save_size)
2987 fprintf (file, " %d regs", reg_save_size);
2988 if (local)
2989 fprintf (file, " %d locals", local);
2990 if (crtl->outgoing_args_size)
2991 fprintf (file, " %d args", crtl->outgoing_args_size);
2992 fprintf (file, "\n");
2993 return;
2994 }
2995
2996 fprintf (file, "\t#\n");
2997 fprintf (file, "\t# Initial Frame Information:\n");
2998 if (sp_offset || !frame_pointer_needed)
2999 fprintf (file, "\t# Entry ---------- 0\n");
3000
3001 /* Sort registers by save slots, so they're printed in the order
3002 they appear in memory, not the order they're saved in. */
3003 for (si=0; si<FIRST_PSEUDO_REGISTER; si++)
3004 slot_map[si] = si;
3005 for (si=0; si<FIRST_PSEUDO_REGISTER-1; si++)
3006 for (sj=si+1; sj<FIRST_PSEUDO_REGISTER; sj++)
3007 if (cfun->machine->reg_save_slot[slot_map[si]]
3008 > cfun->machine->reg_save_slot[slot_map[sj]])
3009 {
3010 int t = slot_map[si];
3011 slot_map[si] = slot_map[sj];
3012 slot_map[sj] = t;
3013 }
3014
3015 sp = 0;
3016 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
3017 {
3018 int rsize;
3019 int r = slot_map[i];
3020 int rss = cfun->machine->reg_save_slot[r];
3021
e756464b
DD
3022 if (!mep_call_saves_register (r))
3023 continue;
3024
3025 if ((r == TP_REGNO || r == GP_REGNO || r == LP_REGNO)
3026 && (!mep_reg_set_in_function (r)
3027 && !mep_interrupt_p ()))
7acf4da6
DD
3028 continue;
3029
3030 rsize = mep_reg_size(r);
3031 skip = rss - (sp+rsize);
3032 if (skip)
3033 fprintf (file, "\t# %3d bytes for alignment\n", skip);
3034 fprintf (file, "\t# %3d bytes for saved %-3s %3d($sp)\n",
3035 rsize, reg_names[r], sp_offset - rss);
3036 sp = rss;
3037 }
3038
3039 skip = reg_save_size - sp;
3040 if (skip)
3041 fprintf (file, "\t# %3d bytes for alignment\n", skip);
3042
3043 if (frame_pointer_needed)
3044 fprintf (file, "\t# FP ---> ---------- %d (sp-%d)\n", reg_save_size, sp_offset-reg_save_size);
3045 if (local)
3046 fprintf (file, "\t# %3d bytes for local vars\n", local);
3047 if (ffill)
3048 fprintf (file, "\t# %3d bytes for alignment\n", ffill);
3049 if (crtl->outgoing_args_size)
3050 fprintf (file, "\t# %3d bytes for outgoing args\n",
3051 crtl->outgoing_args_size);
3052 fprintf (file, "\t# SP ---> ---------- %d\n", sp_offset);
3053 fprintf (file, "\t#\n");
3054}
3055
3056
3057static int mep_prevent_lp_restore = 0;
3058static int mep_sibcall_epilogue = 0;
3059
3060void
3061mep_expand_epilogue (void)
3062{
3063 int i, sp_offset = 0;
3064 int reg_save_size = 0;
3065 int frame_size;
3066 int lp_temp = LP_REGNO, lp_slot = -1;
3067 int really_need_stack_frame = get_frame_size() + crtl->outgoing_args_size;
3068 int interrupt_handler = mep_interrupt_p ();
3069
3070 if (profile_arc_flag == 2)
3071 emit_insn (gen_mep_bb_trace_ret ());
3072
3073 reg_save_size = mep_elimination_offset (ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM);
3074 frame_size = mep_elimination_offset (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM);
3075
e756464b 3076 really_need_stack_frame |= mep_assign_save_slots (reg_save_size);
7acf4da6
DD
3077
3078 if (frame_pointer_needed)
3079 {
3080 /* If we have a frame pointer, we won't have a reliable stack
3081 pointer (alloca, you know), so rebase SP from FP */
3082 emit_move_insn (gen_rtx_REG (SImode, SP_REGNO),
3083 gen_rtx_REG (SImode, FP_REGNO));
3084 sp_offset = reg_save_size;
3085 }
3086 else
3087 {
3088 /* SP is right under our local variable space. Adjust it if
3089 needed. */
3090 sp_offset = reg_save_size + frame_size;
3091 if (sp_offset >= 128)
3092 {
3093 add_constant (SP_REGNO, SP_REGNO, frame_size, 0);
3094 sp_offset -= frame_size;
3095 }
3096 }
3097
3098 /* This is backwards so that we restore the control and coprocessor
3099 registers before the temporary registers we use to restore
3100 them. */
3101 for (i=FIRST_PSEUDO_REGISTER-1; i>=1; i--)
3102 if (mep_call_saves_register (i))
3103 {
3104 enum machine_mode rmode;
3105 int rss = cfun->machine->reg_save_slot[i];
3106
3107 if (mep_reg_size (i) == 8)
3108 rmode = DImode;
3109 else
3110 rmode = SImode;
3111
3112 if ((i == TP_REGNO || i == GP_REGNO || i == LP_REGNO)
3113 && !(mep_reg_set_in_function (i) || interrupt_handler))
3114 continue;
3115 if (mep_prevent_lp_restore && i == LP_REGNO)
3116 continue;
3117 if (!mep_prevent_lp_restore
3118 && !interrupt_handler
3119 && (i == 10 || i == 11))
3120 continue;
3121
3122 if (GR_REGNO_P (i) || LOADABLE_CR_REGNO_P (i))
3123 emit_move_insn (gen_rtx_REG (rmode, i),
3124 gen_rtx_MEM (rmode,
3125 plus_constant (stack_pointer_rtx,
3126 sp_offset-rss)));
3127 else
3128 {
3129 if (i == LP_REGNO && !mep_sibcall_epilogue && !interrupt_handler)
3130 /* Defer this one so we can jump indirect rather than
3131 copying the RA to $lp and "ret". EH epilogues
3132 automatically skip this anyway. */
3133 lp_slot = sp_offset-rss;
3134 else
3135 {
3136 emit_move_insn (gen_rtx_REG (rmode, REGSAVE_CONTROL_TEMP),
3137 gen_rtx_MEM (rmode,
3138 plus_constant (stack_pointer_rtx,
3139 sp_offset-rss)));
3140 emit_move_insn (gen_rtx_REG (rmode, i),
3141 gen_rtx_REG (rmode, REGSAVE_CONTROL_TEMP));
3142 }
3143 }
3144 }
3145 if (lp_slot != -1)
3146 {
3147 /* Restore this one last so we know it will be in the temp
3148 register when we return by jumping indirectly via the temp. */
3149 emit_move_insn (gen_rtx_REG (SImode, REGSAVE_CONTROL_TEMP),
3150 gen_rtx_MEM (SImode,
3151 plus_constant (stack_pointer_rtx,
3152 lp_slot)));
3153 lp_temp = REGSAVE_CONTROL_TEMP;
3154 }
3155
3156
3157 add_constant (SP_REGNO, SP_REGNO, sp_offset, 0);
3158
3159 if (crtl->calls_eh_return && mep_prevent_lp_restore)
3160 emit_insn (gen_addsi3 (gen_rtx_REG (SImode, SP_REGNO),
3161 gen_rtx_REG (SImode, SP_REGNO),
3162 cfun->machine->eh_stack_adjust));
3163
3164 if (mep_sibcall_epilogue)
3165 return;
3166
3167 if (mep_disinterrupt_p ())
3168 emit_insn (gen_mep_enable_int ());
3169
3170 if (mep_prevent_lp_restore)
3171 {
3172 emit_jump_insn (gen_eh_return_internal ());
3173 emit_barrier ();
3174 }
3175 else if (interrupt_handler)
3176 emit_jump_insn (gen_mep_reti ());
3177 else
3178 emit_jump_insn (gen_return_internal (gen_rtx_REG (SImode, lp_temp)));
3179}
3180
3181void
3182mep_expand_eh_return (rtx *operands)
3183{
3184 if (GET_CODE (operands[0]) != REG || REGNO (operands[0]) != LP_REGNO)
3185 {
3186 rtx ra = gen_rtx_REG (Pmode, LP_REGNO);
3187 emit_move_insn (ra, operands[0]);
3188 operands[0] = ra;
3189 }
3190
3191 emit_insn (gen_eh_epilogue (operands[0]));
3192}
3193
3194void
3195mep_emit_eh_epilogue (rtx *operands ATTRIBUTE_UNUSED)
3196{
3197 cfun->machine->eh_stack_adjust = gen_rtx_REG (Pmode, 0);
3198 mep_prevent_lp_restore = 1;
3199 mep_expand_epilogue ();
3200 mep_prevent_lp_restore = 0;
3201}
3202
3203void
3204mep_expand_sibcall_epilogue (void)
3205{
3206 mep_sibcall_epilogue = 1;
3207 mep_expand_epilogue ();
3208 mep_sibcall_epilogue = 0;
3209}
3210
3211static bool
3212mep_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
3213{
3214 if (decl == NULL)
3215 return false;
3216
3217 if (mep_section_tag (DECL_RTL (decl)) == 'f')
3218 return false;
3219
3220 /* Can't call to a sibcall from an interrupt or disinterrupt function. */
3221 if (mep_interrupt_p () || mep_disinterrupt_p ())
3222 return false;
3223
3224 return true;
3225}
3226
3227rtx
3228mep_return_stackadj_rtx (void)
3229{
3230 return gen_rtx_REG (SImode, 10);
3231}
3232
3233rtx
3234mep_return_handler_rtx (void)
3235{
3236 return gen_rtx_REG (SImode, LP_REGNO);
3237}
3238
3239void
3240mep_function_profiler (FILE *file)
3241{
3242 /* Always right at the beginning of the function. */
3243 fprintf (file, "\t# mep function profiler\n");
3244 fprintf (file, "\tadd\t$sp, -8\n");
3245 fprintf (file, "\tsw\t$0, ($sp)\n");
3246 fprintf (file, "\tldc\t$0, $lp\n");
3247 fprintf (file, "\tsw\t$0, 4($sp)\n");
3248 fprintf (file, "\tbsr\t__mep_mcount\n");
3249 fprintf (file, "\tlw\t$0, 4($sp)\n");
3250 fprintf (file, "\tstc\t$0, $lp\n");
3251 fprintf (file, "\tlw\t$0, ($sp)\n");
3252 fprintf (file, "\tadd\t$sp, 8\n\n");
3253}
3254
3255const char *
3256mep_emit_bb_trace_ret (void)
3257{
3258 fprintf (asm_out_file, "\t# end of block profiling\n");
3259 fprintf (asm_out_file, "\tadd\t$sp, -8\n");
3260 fprintf (asm_out_file, "\tsw\t$0, ($sp)\n");
3261 fprintf (asm_out_file, "\tldc\t$0, $lp\n");
3262 fprintf (asm_out_file, "\tsw\t$0, 4($sp)\n");
3263 fprintf (asm_out_file, "\tbsr\t__bb_trace_ret\n");
3264 fprintf (asm_out_file, "\tlw\t$0, 4($sp)\n");
3265 fprintf (asm_out_file, "\tstc\t$0, $lp\n");
3266 fprintf (asm_out_file, "\tlw\t$0, ($sp)\n");
3267 fprintf (asm_out_file, "\tadd\t$sp, 8\n\n");
3268 return "";
3269}
3270
3271#undef SAVE
3272#undef RESTORE
3273\f
3274/* Operand Printing. */
3275
3276void
3277mep_print_operand_address (FILE *stream, rtx address)
3278{
3279 if (GET_CODE (address) == MEM)
3280 address = XEXP (address, 0);
3281 else
3282 /* cf: gcc.dg/asm-4.c. */
3283 gcc_assert (GET_CODE (address) == REG);
3284
3285 mep_print_operand (stream, address, 0);
3286}
3287
3288static struct
3289{
3290 char code;
3291 const char *pattern;
3292 const char *format;
3293}
3294const conversions[] =
3295{
3296 { 0, "r", "0" },
3297 { 0, "m+ri", "3(2)" },
3298 { 0, "mr", "(1)" },
3299 { 0, "ms", "(1)" },
5fb455bc 3300 { 0, "ml", "(1)" },
7acf4da6
DD
3301 { 0, "mLrs", "%lo(3)(2)" },
3302 { 0, "mLr+si", "%lo(4+5)(2)" },
3303 { 0, "m+ru2s", "%tpoff(5)(2)" },
3304 { 0, "m+ru3s", "%sdaoff(5)(2)" },
3305 { 0, "m+r+u2si", "%tpoff(6+7)(2)" },
3306 { 0, "m+ru2+si", "%tpoff(6+7)(2)" },
3307 { 0, "m+r+u3si", "%sdaoff(6+7)(2)" },
3308 { 0, "m+ru3+si", "%sdaoff(6+7)(2)" },
3309 { 0, "mi", "(1)" },
3310 { 0, "m+si", "(2+3)" },
3311 { 0, "m+li", "(2+3)" },
3312 { 0, "i", "0" },
3313 { 0, "s", "0" },
3314 { 0, "+si", "1+2" },
3315 { 0, "+u2si", "%tpoff(3+4)" },
3316 { 0, "+u3si", "%sdaoff(3+4)" },
3317 { 0, "l", "0" },
3318 { 'b', "i", "0" },
3319 { 'B', "i", "0" },
3320 { 'U', "i", "0" },
3321 { 'h', "i", "0" },
3322 { 'h', "Hs", "%hi(1)" },
3323 { 'I', "i", "0" },
3324 { 'I', "u2s", "%tpoff(2)" },
3325 { 'I', "u3s", "%sdaoff(2)" },
3326 { 'I', "+u2si", "%tpoff(3+4)" },
3327 { 'I', "+u3si", "%sdaoff(3+4)" },
3328 { 'J', "i", "0" },
3329 { 'P', "mr", "(1\\+),\\0" },
3330 { 'x', "i", "0" },
3331 { 0, 0, 0 }
3332};
3333
3334static int
3335unique_bit_in (HOST_WIDE_INT i)
3336{
3337 switch (i & 0xff)
3338 {
3339 case 0x01: case 0xfe: return 0;
3340 case 0x02: case 0xfd: return 1;
3341 case 0x04: case 0xfb: return 2;
3342 case 0x08: case 0xf7: return 3;
3343 case 0x10: case 0x7f: return 4;
3344 case 0x20: case 0xbf: return 5;
3345 case 0x40: case 0xdf: return 6;
3346 case 0x80: case 0xef: return 7;
3347 default:
3348 gcc_unreachable ();
3349 }
3350}
3351
3352static int
3353bit_size_for_clip (HOST_WIDE_INT i)
3354{
3355 int rv;
3356
3357 for (rv = 0; rv < 31; rv ++)
3358 if (((HOST_WIDE_INT) 1 << rv) > i)
3359 return rv + 1;
3360 gcc_unreachable ();
3361}
3362
3363/* Print an operand to a assembler instruction. */
3364
3365void
3366mep_print_operand (FILE *file, rtx x, int code)
3367{
3368 int i, j;
3369 const char *real_name;
3370
3371 if (code == '<')
3372 {
3373 /* Print a mnemonic to do CR <- CR moves. Find out which intrinsic
3374 we're using, then skip over the "mep_" part of its name. */
3375 const struct cgen_insn *insn;
3376
3377 if (mep_get_move_insn (mep_cmov, &insn))
3378 fputs (cgen_intrinsics[insn->intrinsic] + 4, file);
3379 else
3380 mep_intrinsic_unavailable (mep_cmov);
3381 return;
3382 }
3383 if (code == 'L')
3384 {
3385 switch (GET_CODE (x))
3386 {
3387 case AND:
3388 fputs ("clr", file);
3389 return;
3390 case IOR:
3391 fputs ("set", file);
3392 return;
3393 case XOR:
3394 fputs ("not", file);
3395 return;
3396 default:
3397 output_operand_lossage ("invalid %%L code");
3398 }
3399 }
3400 if (code == 'M')
3401 {
3402 /* Print the second operand of a CR <- CR move. If we're using
3403 a two-operand instruction (i.e., a real cmov), then just print
3404 the operand normally. If we're using a "reg, reg, immediate"
3405 instruction such as caddi3, print the operand followed by a
3406 zero field. If we're using a three-register instruction,
3407 print the operand twice. */
3408 const struct cgen_insn *insn;
3409
3410 mep_print_operand (file, x, 0);
3411 if (mep_get_move_insn (mep_cmov, &insn)
3412 && insn_data[insn->icode].n_operands == 3)
3413 {
3414 fputs (", ", file);
3415 if (insn_data[insn->icode].operand[2].predicate (x, VOIDmode))
3416 mep_print_operand (file, x, 0);
3417 else
3418 mep_print_operand (file, const0_rtx, 0);
3419 }
3420 return;
3421 }
3422
3423 encode_pattern (x);
3424 for (i = 0; conversions[i].pattern; i++)
3425 if (conversions[i].code == code
3426 && strcmp(conversions[i].pattern, pattern) == 0)
3427 {
3428 for (j = 0; conversions[i].format[j]; j++)
3429 if (conversions[i].format[j] == '\\')
3430 {
3431 fputc (conversions[i].format[j+1], file);
3432 j++;
3433 }
3434 else if (ISDIGIT(conversions[i].format[j]))
3435 {
3436 rtx r = patternr[conversions[i].format[j] - '0'];
3437 switch (GET_CODE (r))
3438 {
3439 case REG:
3440 fprintf (file, "%s", reg_names [REGNO (r)]);
3441 break;
3442 case CONST_INT:
3443 switch (code)
3444 {
3445 case 'b':
3446 fprintf (file, "%d", unique_bit_in (INTVAL (r)));
3447 break;
3448 case 'B':
3449 fprintf (file, "%d", bit_size_for_clip (INTVAL (r)));
3450 break;
3451 case 'h':
3452 fprintf (file, "0x%x", ((int) INTVAL (r) >> 16) & 0xffff);
3453 break;
3454 case 'U':
3455 fprintf (file, "%d", bit_size_for_clip (INTVAL (r)) - 1);
3456 break;
3457 case 'J':
3458 fprintf (file, "0x%x", (int) INTVAL (r) & 0xffff);
3459 break;
3460 case 'x':
3461 if (INTVAL (r) & ~(HOST_WIDE_INT)0xff
3462 && !(INTVAL (r) & 0xff))
3463 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL(r));
3464 else
3465 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL(r));
3466 break;
3467 case 'I':
3468 if (INTVAL (r) & ~(HOST_WIDE_INT)0xff
3469 && conversions[i].format[j+1] == 0)
3470 {
3471 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (r));
3472 fprintf (file, " # 0x%x", (int) INTVAL(r) & 0xffff);
3473 }
3474 else
3475 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL(r));
3476 break;
3477 default:
3478 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL(r));
3479 break;
3480 }
3481 break;
3482 case CONST_DOUBLE:
3483 fprintf(file, "[const_double 0x%lx]",
3484 (unsigned long) CONST_DOUBLE_HIGH(r));
3485 break;
3486 case SYMBOL_REF:
3487 real_name = TARGET_STRIP_NAME_ENCODING (XSTR (r, 0));
3488 assemble_name (file, real_name);
3489 break;
3490 case LABEL_REF:
3491 output_asm_label (r);
3492 break;
3493 default:
3494 fprintf (stderr, "don't know how to print this operand:");
3495 debug_rtx (r);
3496 gcc_unreachable ();
3497 }
3498 }
3499 else
3500 {
3501 if (conversions[i].format[j] == '+'
3502 && (!code || code == 'I')
3503 && ISDIGIT (conversions[i].format[j+1])
3504 && GET_CODE (patternr[conversions[i].format[j+1] - '0']) == CONST_INT
3505 && INTVAL (patternr[conversions[i].format[j+1] - '0']) < 0)
3506 continue;
3507 fputc(conversions[i].format[j], file);
3508 }
3509 break;
3510 }
3511 if (!conversions[i].pattern)
3512 {
3513 error ("unconvertible operand %c %qs", code?code:'-', pattern);
3514 debug_rtx(x);
3515 }
3516
3517 return;
3518}
3519
3520void
3521mep_final_prescan_insn (rtx insn, rtx *operands ATTRIBUTE_UNUSED,
3522 int noperands ATTRIBUTE_UNUSED)
3523{
3524 /* Despite the fact that MeP is perfectly capable of branching and
3525 doing something else in the same bundle, gcc does jump
3526 optimization *after* scheduling, so we cannot trust the bundling
3527 flags on jump instructions. */
3528 if (GET_MODE (insn) == BImode
3529 && get_attr_slots (insn) != SLOTS_CORE)
3530 fputc ('+', asm_out_file);
3531}
3532
3533/* Function args in registers. */
3534
3535static void
3536mep_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
3537 enum machine_mode mode ATTRIBUTE_UNUSED,
3538 tree type ATTRIBUTE_UNUSED, int *pretend_size,
3539 int second_time ATTRIBUTE_UNUSED)
3540{
3541 int nsave = 4 - (cum->nregs + 1);
3542
3543 if (nsave > 0)
3544 cfun->machine->arg_regs_to_save = nsave;
3545 *pretend_size = nsave * 4;
3546}
3547
3548static int
3549bytesize (const_tree type, enum machine_mode mode)
3550{
3551 if (mode == BLKmode)
3552 return int_size_in_bytes (type);
3553 return GET_MODE_SIZE (mode);
3554}
3555
3556static rtx
3557mep_expand_builtin_saveregs (void)
3558{
3559 int bufsize, i, ns;
3560 rtx regbuf;
3561
3562 ns = cfun->machine->arg_regs_to_save;
683a1be6
DD
3563 if (TARGET_IVC2)
3564 {
3565 bufsize = 8 * ((ns + 1) / 2) + 8 * ns;
3566 regbuf = assign_stack_local (SImode, bufsize, 64);
3567 }
3568 else
3569 {
3570 bufsize = ns * 4;
3571 regbuf = assign_stack_local (SImode, bufsize, 32);
3572 }
7acf4da6
DD
3573
3574 move_block_from_reg (5-ns, regbuf, ns);
3575
3576 if (TARGET_IVC2)
3577 {
3578 rtx tmp = gen_rtx_MEM (DImode, XEXP (regbuf, 0));
683a1be6 3579 int ofs = 8 * ((ns+1)/2);
7acf4da6
DD
3580
3581 for (i=0; i<ns; i++)
3582 {
3583 int rn = (4-ns) + i + 49;
3584 rtx ptr;
3585
3586 ptr = offset_address (tmp, GEN_INT (ofs), 2);
3587 emit_move_insn (ptr, gen_rtx_REG (DImode, rn));
3588 ofs += 8;
3589 }
3590 }
3591 return XEXP (regbuf, 0);
3592}
3593
3594#define VECTOR_TYPE_P(t) (TREE_CODE(t) == VECTOR_TYPE)
3595
3596static tree
3597mep_build_builtin_va_list (void)
3598{
3599 tree f_next_gp, f_next_gp_limit, f_next_cop, f_next_stack;
3600 tree record;
3601
3602
3603 record = (*lang_hooks.types.make_type) (RECORD_TYPE);
3604
3605 f_next_gp = build_decl (BUILTINS_LOCATION, FIELD_DECL,
3606 get_identifier ("__va_next_gp"), ptr_type_node);
3607 f_next_gp_limit = build_decl (BUILTINS_LOCATION, FIELD_DECL,
3608 get_identifier ("__va_next_gp_limit"),
3609 ptr_type_node);
3610 f_next_cop = build_decl (BUILTINS_LOCATION, FIELD_DECL, get_identifier ("__va_next_cop"),
3611 ptr_type_node);
3612 f_next_stack = build_decl (BUILTINS_LOCATION, FIELD_DECL, get_identifier ("__va_next_stack"),
3613 ptr_type_node);
3614
3615 DECL_FIELD_CONTEXT (f_next_gp) = record;
3616 DECL_FIELD_CONTEXT (f_next_gp_limit) = record;
3617 DECL_FIELD_CONTEXT (f_next_cop) = record;
3618 DECL_FIELD_CONTEXT (f_next_stack) = record;
3619
3620 TYPE_FIELDS (record) = f_next_gp;
3621 TREE_CHAIN (f_next_gp) = f_next_gp_limit;
3622 TREE_CHAIN (f_next_gp_limit) = f_next_cop;
3623 TREE_CHAIN (f_next_cop) = f_next_stack;
3624
3625 layout_type (record);
3626
3627 return record;
3628}
3629
3630static void
3631mep_expand_va_start (tree valist, rtx nextarg)
3632{
3633 tree f_next_gp, f_next_gp_limit, f_next_cop, f_next_stack;
3634 tree next_gp, next_gp_limit, next_cop, next_stack;
3635 tree t, u;
3636 int ns;
3637
3638 ns = cfun->machine->arg_regs_to_save;
3639
3640 f_next_gp = TYPE_FIELDS (va_list_type_node);
3641 f_next_gp_limit = TREE_CHAIN (f_next_gp);
3642 f_next_cop = TREE_CHAIN (f_next_gp_limit);
3643 f_next_stack = TREE_CHAIN (f_next_cop);
3644
3645 next_gp = build3 (COMPONENT_REF, TREE_TYPE (f_next_gp), valist, f_next_gp,
3646 NULL_TREE);
3647 next_gp_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_gp_limit),
3648 valist, f_next_gp_limit, NULL_TREE);
3649 next_cop = build3 (COMPONENT_REF, TREE_TYPE (f_next_cop), valist, f_next_cop,
3650 NULL_TREE);
3651 next_stack = build3 (COMPONENT_REF, TREE_TYPE (f_next_stack),
3652 valist, f_next_stack, NULL_TREE);
3653
3654 /* va_list.next_gp = expand_builtin_saveregs (); */
3655 u = make_tree (sizetype, expand_builtin_saveregs ());
3656 u = fold_convert (ptr_type_node, u);
3657 t = build2 (MODIFY_EXPR, ptr_type_node, next_gp, u);
3658 TREE_SIDE_EFFECTS (t) = 1;
3659 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
3660
3661 /* va_list.next_gp_limit = va_list.next_gp + 4 * ns; */
3662 u = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, u,
3663 size_int (4 * ns));
3664 t = build2 (MODIFY_EXPR, ptr_type_node, next_gp_limit, u);
3665 TREE_SIDE_EFFECTS (t) = 1;
3666 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
3667
683a1be6
DD
3668 u = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, u,
3669 size_int (8 * ((ns+1)/2)));
3670 /* va_list.next_cop = ROUND_UP(va_list.next_gp_limit,8); */
7acf4da6
DD
3671 t = build2 (MODIFY_EXPR, ptr_type_node, next_cop, u);
3672 TREE_SIDE_EFFECTS (t) = 1;
3673 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
3674
3675 /* va_list.next_stack = nextarg; */
3676 u = make_tree (ptr_type_node, nextarg);
3677 t = build2 (MODIFY_EXPR, ptr_type_node, next_stack, u);
3678 TREE_SIDE_EFFECTS (t) = 1;
3679 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
3680}
3681
3682static tree
3683mep_gimplify_va_arg_expr (tree valist, tree type,
3684 tree *pre_p, tree *post_p ATTRIBUTE_UNUSED)
3685{
3686 HOST_WIDE_INT size, rsize;
3687 bool by_reference, ivc2_vec;
3688 tree f_next_gp, f_next_gp_limit, f_next_cop, f_next_stack;
3689 tree next_gp, next_gp_limit, next_cop, next_stack;
3690 tree label_sover, label_selse;
3691 tree tmp, res_addr;
3692
3693 ivc2_vec = TARGET_IVC2 && VECTOR_TYPE_P (type);
3694
3695 size = int_size_in_bytes (type);
3696 by_reference = (size > (ivc2_vec ? 8 : 4)) || (size <= 0);
3697
3698 if (by_reference)
3699 {
3700 type = build_pointer_type (type);
3701 size = 4;
3702 }
3703 rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
3704
3705 f_next_gp = TYPE_FIELDS (va_list_type_node);
3706 f_next_gp_limit = TREE_CHAIN (f_next_gp);
3707 f_next_cop = TREE_CHAIN (f_next_gp_limit);
3708 f_next_stack = TREE_CHAIN (f_next_cop);
3709
3710 next_gp = build3 (COMPONENT_REF, TREE_TYPE (f_next_gp), valist, f_next_gp,
3711 NULL_TREE);
3712 next_gp_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_gp_limit),
3713 valist, f_next_gp_limit, NULL_TREE);
3714 next_cop = build3 (COMPONENT_REF, TREE_TYPE (f_next_cop), valist, f_next_cop,
3715 NULL_TREE);
3716 next_stack = build3 (COMPONENT_REF, TREE_TYPE (f_next_stack),
3717 valist, f_next_stack, NULL_TREE);
3718
3719 /* if f_next_gp < f_next_gp_limit
3720 IF (VECTOR_P && IVC2)
3721 val = *f_next_cop;
3722 ELSE
3723 val = *f_next_gp;
3724 f_next_gp += 4;
3725 f_next_cop += 8;
3726 else
3727 label_selse:
3728 val = *f_next_stack;
3729 f_next_stack += rsize;
3730 label_sover:
3731 */
3732
3733 label_sover = create_artificial_label (UNKNOWN_LOCATION);
3734 label_selse = create_artificial_label (UNKNOWN_LOCATION);
3735 res_addr = create_tmp_var (ptr_type_node, NULL);
3736
3737 tmp = build2 (GE_EXPR, boolean_type_node, next_gp,
3738 unshare_expr (next_gp_limit));
3739 tmp = build3 (COND_EXPR, void_type_node, tmp,
3740 build1 (GOTO_EXPR, void_type_node,
3741 unshare_expr (label_selse)),
3742 NULL_TREE);
3743 gimplify_and_add (tmp, pre_p);
3744
3745 if (ivc2_vec)
3746 {
3747 tmp = build2 (MODIFY_EXPR, void_type_node, res_addr, next_cop);
3748 gimplify_and_add (tmp, pre_p);
3749 }
3750 else
3751 {
3752 tmp = build2 (MODIFY_EXPR, void_type_node, res_addr, next_gp);
3753 gimplify_and_add (tmp, pre_p);
3754 }
3755
3756 tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node,
3757 unshare_expr (next_gp), size_int (4));
3758 gimplify_assign (unshare_expr (next_gp), tmp, pre_p);
3759
3760 tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node,
3761 unshare_expr (next_cop), size_int (8));
3762 gimplify_assign (unshare_expr (next_cop), tmp, pre_p);
3763
3764 tmp = build1 (GOTO_EXPR, void_type_node, unshare_expr (label_sover));
3765 gimplify_and_add (tmp, pre_p);
3766
3767 /* - - */
3768
3769 tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (label_selse));
3770 gimplify_and_add (tmp, pre_p);
3771
3772 tmp = build2 (MODIFY_EXPR, void_type_node, res_addr, unshare_expr (next_stack));
3773 gimplify_and_add (tmp, pre_p);
3774
3775 tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node,
3776 unshare_expr (next_stack), size_int (rsize));
3777 gimplify_assign (unshare_expr (next_stack), tmp, pre_p);
3778
3779 /* - - */
3780
3781 tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (label_sover));
3782 gimplify_and_add (tmp, pre_p);
3783
3784 res_addr = fold_convert (build_pointer_type (type), res_addr);
3785
3786 if (by_reference)
3787 res_addr = build_va_arg_indirect_ref (res_addr);
3788
3789 return build_va_arg_indirect_ref (res_addr);
3790}
3791
3792void
3793mep_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
3794 rtx libname ATTRIBUTE_UNUSED,
3795 tree fndecl ATTRIBUTE_UNUSED)
3796{
3797 pcum->nregs = 0;
3798
3799 if (fntype && lookup_attribute ("vliw", TYPE_ATTRIBUTES (fntype)))
3800 pcum->vliw = 1;
3801 else
3802 pcum->vliw = 0;
3803}
3804
3805rtx
3806mep_function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode,
3807 tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
3808{
3809 /* VOIDmode is a signal for the backend to pass data to the call
3810 expander via the second operand to the call pattern. We use
3811 this to determine whether to use "jsr" or "jsrv". */
3812 if (mode == VOIDmode)
3813 return GEN_INT (cum.vliw);
3814
3815 /* If we havn't run out of argument registers, return the next. */
3816 if (cum.nregs < 4)
3817 {
3818 if (type && TARGET_IVC2 && VECTOR_TYPE_P (type))
3819 return gen_rtx_REG (mode, cum.nregs + 49);
3820 else
3821 return gen_rtx_REG (mode, cum.nregs + 1);
3822 }
3823
3824 /* Otherwise the argument goes on the stack. */
3825 return NULL_RTX;
3826}
3827
3828static bool
3829mep_pass_by_reference (CUMULATIVE_ARGS * cum ATTRIBUTE_UNUSED,
3830 enum machine_mode mode,
3831 const_tree type,
3832 bool named ATTRIBUTE_UNUSED)
3833{
3834 int size = bytesize (type, mode);
e756464b
DD
3835
3836 /* This is non-obvious, but yes, large values passed after we've run
3837 out of registers are *still* passed by reference - we put the
3838 address of the parameter on the stack, as well as putting the
3839 parameter itself elsewhere on the stack. */
3840
3841 if (size <= 0 || size > 8)
3842 return true;
3843 if (size <= 4)
3844 return false;
3845 if (TARGET_IVC2 && cum->nregs < 4 && type != NULL_TREE && VECTOR_TYPE_P (type))
3846 return false;
3847 return true;
7acf4da6
DD
3848}
3849
3850void
3851mep_arg_advance (CUMULATIVE_ARGS *pcum,
3852 enum machine_mode mode ATTRIBUTE_UNUSED,
3853 tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
3854{
3855 pcum->nregs += 1;
3856}
3857
3858bool
3859mep_return_in_memory (const_tree type, const_tree decl ATTRIBUTE_UNUSED)
3860{
3861 int size = bytesize (type, BLKmode);
3862 if (TARGET_IVC2 && VECTOR_TYPE_P (type))
e756464b
DD
3863 return size > 0 && size <= 8 ? 0 : 1;
3864 return size > 0 && size <= 4 ? 0 : 1;
7acf4da6
DD
3865}
3866
3867static bool
3868mep_narrow_volatile_bitfield (void)
3869{
3870 return true;
3871 return false;
3872}
3873
3874/* Implement FUNCTION_VALUE. All values are returned in $0. */
3875
3876rtx
3877mep_function_value (tree type, tree func ATTRIBUTE_UNUSED)
3878{
3879 if (TARGET_IVC2 && VECTOR_TYPE_P (type))
3880 return gen_rtx_REG (TYPE_MODE (type), 48);
3881 return gen_rtx_REG (TYPE_MODE (type), RETURN_VALUE_REGNUM);
3882}
3883
3884/* Implement LIBCALL_VALUE, using the same rules as mep_function_value. */
3885
3886rtx
3887mep_libcall_value (enum machine_mode mode)
3888{
3889 return gen_rtx_REG (mode, RETURN_VALUE_REGNUM);
3890}
3891
3892/* Handle pipeline hazards. */
3893
3894typedef enum { op_none, op_stc, op_fsft, op_ret } op_num;
3895static const char *opnames[] = { "", "stc", "fsft", "ret" };
3896
3897static int prev_opcode = 0;
3898
3899/* This isn't as optimal as it could be, because we don't know what
3900 control register the STC opcode is storing in. We only need to add
3901 the nop if it's the relevent register, but we add it for irrelevent
3902 registers also. */
3903
3904void
3905mep_asm_output_opcode (FILE *file, const char *ptr)
3906{
3907 int this_opcode = op_none;
3908 const char *hazard = 0;
3909
3910 switch (*ptr)
3911 {
3912 case 'f':
3913 if (strncmp (ptr, "fsft", 4) == 0 && !ISGRAPH (ptr[4]))
3914 this_opcode = op_fsft;
3915 break;
3916 case 'r':
3917 if (strncmp (ptr, "ret", 3) == 0 && !ISGRAPH (ptr[3]))
3918 this_opcode = op_ret;
3919 break;
3920 case 's':
3921 if (strncmp (ptr, "stc", 3) == 0 && !ISGRAPH (ptr[3]))
3922 this_opcode = op_stc;
3923 break;
3924 }
3925
3926 if (prev_opcode == op_stc && this_opcode == op_fsft)
3927 hazard = "nop";
3928 if (prev_opcode == op_stc && this_opcode == op_ret)
3929 hazard = "nop";
3930
3931 if (hazard)
3932 fprintf(file, "%s\t# %s-%s hazard\n\t",
3933 hazard, opnames[prev_opcode], opnames[this_opcode]);
3934
3935 prev_opcode = this_opcode;
3936}
3937
3938/* Handle attributes. */
3939
3940static tree
3941mep_validate_based_tiny (tree *node, tree name, tree args,
3942 int flags ATTRIBUTE_UNUSED, bool *no_add)
3943{
3944 if (TREE_CODE (*node) != VAR_DECL
3945 && TREE_CODE (*node) != POINTER_TYPE
3946 && TREE_CODE (*node) != TYPE_DECL)
3947 {
3948 warning (0, "%qE attribute only applies to variables", name);
3949 *no_add = true;
3950 }
3951 else if (args == NULL_TREE && TREE_CODE (*node) == VAR_DECL)
3952 {
3953 if (! (TREE_PUBLIC (*node) || TREE_STATIC (*node)))
3954 {
3955 warning (0, "address region attributes not allowed with auto storage class");
3956 *no_add = true;
3957 }
3958 /* Ignore storage attribute of pointed to variable: char __far * x; */
3959 if (TREE_TYPE (*node) && TREE_CODE (TREE_TYPE (*node)) == POINTER_TYPE)
3960 {
3961 warning (0, "address region attributes on pointed-to types ignored");
3962 *no_add = true;
3963 }
3964 }
3965
3966 return NULL_TREE;
3967}
3968
3969static int
3970mep_multiple_address_regions (tree list, bool check_section_attr)
3971{
3972 tree a;
3973 int count_sections = 0;
3974 int section_attr_count = 0;
3975
3976 for (a = list; a; a = TREE_CHAIN (a))
3977 {
3978 if (is_attribute_p ("based", TREE_PURPOSE (a))
3979 || is_attribute_p ("tiny", TREE_PURPOSE (a))
3980 || is_attribute_p ("near", TREE_PURPOSE (a))
3981 || is_attribute_p ("far", TREE_PURPOSE (a))
3982 || is_attribute_p ("io", TREE_PURPOSE (a)))
3983 count_sections ++;
3984 if (check_section_attr)
3985 section_attr_count += is_attribute_p ("section", TREE_PURPOSE (a));
3986 }
3987
3988 if (check_section_attr)
3989 return section_attr_count;
3990 else
3991 return count_sections;
3992}
3993
3994#define MEP_ATTRIBUTES(decl) \
3995 (TYPE_P (decl)) ? TYPE_ATTRIBUTES (decl) \
3996 : DECL_ATTRIBUTES (decl) \
3997 ? (DECL_ATTRIBUTES (decl)) \
3998 : TYPE_ATTRIBUTES (TREE_TYPE (decl))
3999
4000static tree
4001mep_validate_near_far (tree *node, tree name, tree args,
4002 int flags ATTRIBUTE_UNUSED, bool *no_add)
4003{
4004 if (TREE_CODE (*node) != VAR_DECL
4005 && TREE_CODE (*node) != FUNCTION_DECL
4006 && TREE_CODE (*node) != METHOD_TYPE
4007 && TREE_CODE (*node) != POINTER_TYPE
4008 && TREE_CODE (*node) != TYPE_DECL)
4009 {
4010 warning (0, "%qE attribute only applies to variables and functions",
4011 name);
4012 *no_add = true;
4013 }
4014 else if (args == NULL_TREE && TREE_CODE (*node) == VAR_DECL)
4015 {
4016 if (! (TREE_PUBLIC (*node) || TREE_STATIC (*node)))
4017 {
4018 warning (0, "address region attributes not allowed with auto storage class");
4019 *no_add = true;
4020 }
4021 /* Ignore storage attribute of pointed to variable: char __far * x; */
4022 if (TREE_TYPE (*node) && TREE_CODE (TREE_TYPE (*node)) == POINTER_TYPE)
4023 {
4024 warning (0, "address region attributes on pointed-to types ignored");
4025 *no_add = true;
4026 }
4027 }
4028 else if (mep_multiple_address_regions (MEP_ATTRIBUTES (*node), false) > 0)
4029 {
4030 warning (0, "duplicate address region attribute %qE in declaration of %qE on line %d",
4031 name, DECL_NAME (*node), DECL_SOURCE_LINE (*node));
4032 DECL_ATTRIBUTES (*node) = NULL_TREE;
4033 }
4034 return NULL_TREE;
4035}
4036
4037static tree
4038mep_validate_disinterrupt (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
4039 int flags ATTRIBUTE_UNUSED, bool *no_add)
4040{
4041 if (TREE_CODE (*node) != FUNCTION_DECL
4042 && TREE_CODE (*node) != METHOD_TYPE)
4043 {
4044 warning (0, "%qE attribute only applies to functions", name);
4045 *no_add = true;
4046 }
4047 return NULL_TREE;
4048}
4049
4050static tree
4051mep_validate_interrupt (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
4052 int flags ATTRIBUTE_UNUSED, bool *no_add)
4053{
4054 tree function_type;
4055
4056 if (TREE_CODE (*node) != FUNCTION_DECL)
4057 {
4058 warning (0, "%qE attribute only applies to functions", name);
4059 *no_add = true;
4060 return NULL_TREE;
4061 }
4062
4063 if (DECL_DECLARED_INLINE_P (*node))
4064 error ("cannot inline interrupt function %qE", DECL_NAME (*node));
4065 DECL_UNINLINABLE (*node) = 1;
4066
4067 function_type = TREE_TYPE (*node);
4068
4069 if (TREE_TYPE (function_type) != void_type_node)
4070 error ("interrupt function must have return type of void");
4071
4072 if (TYPE_ARG_TYPES (function_type)
4073 && (TREE_VALUE (TYPE_ARG_TYPES (function_type)) != void_type_node
4074 || TREE_CHAIN (TYPE_ARG_TYPES (function_type)) != NULL_TREE))
4075 error ("interrupt function must have no arguments");
4076
4077 return NULL_TREE;
4078}
4079
4080static tree
4081mep_validate_io_cb (tree *node, tree name, tree args,
4082 int flags ATTRIBUTE_UNUSED, bool *no_add)
4083{
4084 if (TREE_CODE (*node) != VAR_DECL)
4085 {
4086 warning (0, "%qE attribute only applies to variables", name);
4087 *no_add = true;
4088 }
4089
4090 if (args != NULL_TREE)
4091 {
4092 if (TREE_CODE (TREE_VALUE (args)) == NON_LVALUE_EXPR)
4093 TREE_VALUE (args) = TREE_OPERAND (TREE_VALUE (args), 0);
4094 if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST)
4095 {
4096 warning (0, "%qE attribute allows only an integer constant argument",
4097 name);
4098 *no_add = true;
4099 }
4100 }
4101
4102 if (*no_add == false && !TARGET_IO_NO_VOLATILE)
4103 TREE_THIS_VOLATILE (*node) = 1;
4104
4105 return NULL_TREE;
4106}
4107
4108static tree
4109mep_validate_vliw (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
4110 int flags ATTRIBUTE_UNUSED, bool *no_add)
4111{
4112 if (TREE_CODE (*node) != FUNCTION_TYPE
4113 && TREE_CODE (*node) != FUNCTION_DECL
4114 && TREE_CODE (*node) != METHOD_TYPE
4115 && TREE_CODE (*node) != FIELD_DECL
4116 && TREE_CODE (*node) != TYPE_DECL)
4117 {
4118 static int gave_pointer_note = 0;
4119 static int gave_array_note = 0;
4120 static const char * given_type = NULL;
4121
4122 given_type = tree_code_name[TREE_CODE (*node)];
4123 if (TREE_CODE (*node) == POINTER_TYPE)
4124 given_type = "pointers";
4125 if (TREE_CODE (*node) == ARRAY_TYPE)
4126 given_type = "arrays";
4127
4128 if (given_type)
4129 warning (0, "%qE attribute only applies to functions, not %s",
4130 name, given_type);
4131 else
4132 warning (0, "%qE attribute only applies to functions",
4133 name);
4134 *no_add = true;
4135
4136 if (TREE_CODE (*node) == POINTER_TYPE
4137 && !gave_pointer_note)
4138 {
4139 inform (input_location, "To describe a pointer to a VLIW function, use syntax like this:");
4140 inform (input_location, " typedef int (__vliw *vfuncptr) ();");
4141 gave_pointer_note = 1;
4142 }
4143
4144 if (TREE_CODE (*node) == ARRAY_TYPE
4145 && !gave_array_note)
4146 {
4147 inform (input_location, "To describe an array of VLIW function pointers, use syntax like this:");
4148 inform (input_location, " typedef int (__vliw *vfuncptr[]) ();");
4149 gave_array_note = 1;
4150 }
4151 }
4152 if (!TARGET_VLIW)
4153 error ("VLIW functions are not allowed without a VLIW configuration");
4154 return NULL_TREE;
4155}
4156
4157static const struct attribute_spec mep_attribute_table[11] =
4158{
4159 /* name min max decl type func handler */
4160 { "based", 0, 0, false, false, false, mep_validate_based_tiny },
4161 { "tiny", 0, 0, false, false, false, mep_validate_based_tiny },
4162 { "near", 0, 0, false, false, false, mep_validate_near_far },
4163 { "far", 0, 0, false, false, false, mep_validate_near_far },
4164 { "disinterrupt", 0, 0, false, false, false, mep_validate_disinterrupt },
4165 { "interrupt", 0, 0, false, false, false, mep_validate_interrupt },
4166 { "io", 0, 1, false, false, false, mep_validate_io_cb },
4167 { "cb", 0, 1, false, false, false, mep_validate_io_cb },
4168 { "vliw", 0, 0, false, true, false, mep_validate_vliw },
4169 { NULL, 0, 0, false, false, false, NULL }
4170};
4171
4172static bool
4173mep_function_attribute_inlinable_p (const_tree callee)
4174{
4175 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (callee));
4176 if (!attrs) attrs = DECL_ATTRIBUTES (callee);
4177 return (lookup_attribute ("disinterrupt", attrs) == 0
4178 && lookup_attribute ("interrupt", attrs) == 0);
4179}
4180
ae30c1fa 4181static bool
5cec9f59 4182mep_can_inline_p (tree caller, tree callee)
ae30c1fa
DD
4183{
4184 if (TREE_CODE (callee) == ADDR_EXPR)
4185 callee = TREE_OPERAND (callee, 0);
4186
82e45095 4187 if (!mep_vliw_function_p (caller)
ae30c1fa
DD
4188 && mep_vliw_function_p (callee))
4189 {
82e45095 4190 return false;
ae30c1fa 4191 }
82e45095 4192 return true;
ae30c1fa
DD
4193}
4194
7acf4da6
DD
4195#define FUNC_CALL 1
4196#define FUNC_DISINTERRUPT 2
4197
4198
4199struct GTY(()) pragma_entry {
4200 int used;
4201 int flag;
4202 const char *funcname;
4203};
4204typedef struct pragma_entry pragma_entry;
4205
4206/* Hash table of farcall-tagged sections. */
4207static GTY((param_is (pragma_entry))) htab_t pragma_htab;
4208
4209static int
4210pragma_entry_eq (const void *p1, const void *p2)
4211{
4212 const pragma_entry *old = (const pragma_entry *) p1;
4213 const char *new_name = (const char *) p2;
4214
4215 return strcmp (old->funcname, new_name) == 0;
4216}
4217
4218static hashval_t
4219pragma_entry_hash (const void *p)
4220{
4221 const pragma_entry *old = (const pragma_entry *) p;
4222 return htab_hash_string (old->funcname);
4223}
4224
4225static void
4226mep_note_pragma_flag (const char *funcname, int flag)
4227{
4228 pragma_entry **slot;
4229
4230 if (!pragma_htab)
4231 pragma_htab = htab_create_ggc (31, pragma_entry_hash,
4232 pragma_entry_eq, NULL);
4233
4234 slot = (pragma_entry **)
4235 htab_find_slot_with_hash (pragma_htab, funcname,
4236 htab_hash_string (funcname), INSERT);
4237
4238 if (!*slot)
4239 {
4240 *slot = GGC_NEW (pragma_entry);
4241 (*slot)->flag = 0;
4242 (*slot)->used = 0;
4243 (*slot)->funcname = ggc_strdup (funcname);
4244 }
4245 (*slot)->flag |= flag;
4246}
4247
4248static bool
4249mep_lookup_pragma_flag (const char *funcname, int flag)
4250{
4251 pragma_entry **slot;
4252
4253 if (!pragma_htab)
4254 return false;
4255
4256 if (funcname[0] == '@' && funcname[2] == '.')
4257 funcname += 3;
4258
4259 slot = (pragma_entry **)
4260 htab_find_slot_with_hash (pragma_htab, funcname,
4261 htab_hash_string (funcname), NO_INSERT);
4262 if (slot && *slot && ((*slot)->flag & flag))
4263 {
4264 (*slot)->used |= flag;
4265 return true;
4266 }
4267 return false;
4268}
4269
4270bool
4271mep_lookup_pragma_call (const char *funcname)
4272{
4273 return mep_lookup_pragma_flag (funcname, FUNC_CALL);
4274}
4275
4276void
4277mep_note_pragma_call (const char *funcname)
4278{
4279 mep_note_pragma_flag (funcname, FUNC_CALL);
4280}
4281
4282bool
4283mep_lookup_pragma_disinterrupt (const char *funcname)
4284{
4285 return mep_lookup_pragma_flag (funcname, FUNC_DISINTERRUPT);
4286}
4287
4288void
4289mep_note_pragma_disinterrupt (const char *funcname)
4290{
4291 mep_note_pragma_flag (funcname, FUNC_DISINTERRUPT);
4292}
4293
4294static int
4295note_unused_pragma_disinterrupt (void **slot, void *data ATTRIBUTE_UNUSED)
4296{
4297 const pragma_entry *d = (const pragma_entry *)(*slot);
4298
4299 if ((d->flag & FUNC_DISINTERRUPT)
4300 && !(d->used & FUNC_DISINTERRUPT))
4301 warning (0, "\"#pragma disinterrupt %s\" not used", d->funcname);
4302 return 1;
4303}
4304
4305void
4306mep_file_cleanups (void)
4307{
4308 if (pragma_htab)
4309 htab_traverse (pragma_htab, note_unused_pragma_disinterrupt, NULL);
4310}
4311
4312
4313static int
4314mep_attrlist_to_encoding (tree list, tree decl)
4315{
4316 if (mep_multiple_address_regions (list, false) > 1)
4317 {
4318 warning (0, "duplicate address region attribute %qE in declaration of %qE on line %d",
4319 TREE_PURPOSE (TREE_CHAIN (list)),
4320 DECL_NAME (decl),
4321 DECL_SOURCE_LINE (decl));
4322 TREE_CHAIN (list) = NULL_TREE;
4323 }
4324
4325 while (list)
4326 {
4327 if (is_attribute_p ("based", TREE_PURPOSE (list)))
4328 return 'b';
4329 if (is_attribute_p ("tiny", TREE_PURPOSE (list)))
4330 return 't';
4331 if (is_attribute_p ("near", TREE_PURPOSE (list)))
4332 return 'n';
4333 if (is_attribute_p ("far", TREE_PURPOSE (list)))
4334 return 'f';
4335 if (is_attribute_p ("io", TREE_PURPOSE (list)))
4336 {
4337 if (TREE_VALUE (list)
4338 && TREE_VALUE (TREE_VALUE (list))
4339 && TREE_CODE (TREE_VALUE (TREE_VALUE (list))) == INTEGER_CST)
4340 {
4341 int location = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE(list)));
4342 if (location >= 0
4343 && location <= 0x1000000)
4344 return 'i';
4345 }
4346 return 'I';
4347 }
4348 if (is_attribute_p ("cb", TREE_PURPOSE (list)))
4349 return 'c';
4350 list = TREE_CHAIN (list);
4351 }
4352 if (TARGET_TF
4353 && TREE_CODE (decl) == FUNCTION_DECL
4354 && DECL_SECTION_NAME (decl) == 0)
4355 return 'f';
4356 return 0;
4357}
4358
4359static int
4360mep_comp_type_attributes (const_tree t1, const_tree t2)
4361{
4362 int vliw1, vliw2;
4363
4364 vliw1 = (lookup_attribute ("vliw", TYPE_ATTRIBUTES (t1)) != 0);
4365 vliw2 = (lookup_attribute ("vliw", TYPE_ATTRIBUTES (t2)) != 0);
4366
4367 if (vliw1 != vliw2)
4368 return 0;
4369
4370 return 1;
4371}
4372
4373static void
4374mep_insert_attributes (tree decl, tree *attributes)
4375{
4376 int size;
4377 const char *secname = 0;
4378 tree attrib, attrlist;
4379 char encoding;
4380
4381 if (TREE_CODE (decl) == FUNCTION_DECL)
4382 {
4383 const char *funcname = IDENTIFIER_POINTER (DECL_NAME (decl));
4384
4385 if (mep_lookup_pragma_disinterrupt (funcname))
4386 {
4387 attrib = build_tree_list (get_identifier ("disinterrupt"), NULL_TREE);
4388 *attributes = chainon (*attributes, attrib);
4389 }
4390 }
4391
4392 if (TREE_CODE (decl) != VAR_DECL
4393 || ! (TREE_PUBLIC (decl) || TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
4394 return;
4395
4396 if (TREE_READONLY (decl) && TARGET_DC)
4397 /* -mdc means that const variables default to the near section,
4398 regardless of the size cutoff. */
4399 return;
4400
4401 /* User specified an attribute, so override the default.
4402 Ignore storage attribute of pointed to variable. char __far * x; */
4403 if (! (TREE_TYPE (decl) && TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE))
4404 {
4405 if (TYPE_P (decl) && TYPE_ATTRIBUTES (decl) && *attributes)
4406 TYPE_ATTRIBUTES (decl) = NULL_TREE;
4407 else if (DECL_ATTRIBUTES (decl) && *attributes)
4408 DECL_ATTRIBUTES (decl) = NULL_TREE;
4409 }
4410
4411 attrlist = *attributes ? *attributes : DECL_ATTRIBUTES (decl);
4412 encoding = mep_attrlist_to_encoding (attrlist, decl);
4413 if (!encoding && TYPE_P (TREE_TYPE (decl)))
4414 {
4415 attrlist = TYPE_ATTRIBUTES (TREE_TYPE (decl));
4416 encoding = mep_attrlist_to_encoding (attrlist, decl);
4417 }
4418 if (encoding)
4419 {
4420 /* This means that the declaration has a specific section
4421 attribute, so we should not apply the default rules. */
4422
4423 if (encoding == 'i' || encoding == 'I')
4424 {
4425 tree attr = lookup_attribute ("io", attrlist);
4426 if (attr
4427 && TREE_VALUE (attr)
4428 && TREE_VALUE (TREE_VALUE(attr)))
4429 {
4430 int location = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE(attr)));
4431 static tree previous_value = 0;
4432 static int previous_location = 0;
4433 static tree previous_name = 0;
4434
4435 /* We take advantage of the fact that gcc will reuse the
4436 same tree pointer when applying an attribute to a
4437 list of decls, but produce a new tree for attributes
4438 on separate source lines, even when they're textually
4439 identical. This is the behavior we want. */
4440 if (TREE_VALUE (attr) == previous_value
4441 && location == previous_location)
4442 {
4443 warning(0, "__io address 0x%x is the same for %qE and %qE",
4444 location, previous_name, DECL_NAME (decl));
4445 }
4446 previous_name = DECL_NAME (decl);
4447 previous_location = location;
4448 previous_value = TREE_VALUE (attr);
4449 }
4450 }
4451 return;
4452 }
4453
4454
4455 /* Declarations of arrays can change size. Don't trust them. */
4456 if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
4457 size = 0;
4458 else
4459 size = int_size_in_bytes (TREE_TYPE (decl));
4460
4461 if (TARGET_RAND_TPGP && size <= 4 && size > 0)
4462 {
4463 if (TREE_PUBLIC (decl)
4464 || DECL_EXTERNAL (decl)
4465 || TREE_STATIC (decl))
4466 {
4467 const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
4468 int key = 0;
4469
4470 while (*name)
4471 key += *name++;
4472
4473 switch (key & 3)
4474 {
4475 case 0:
4476 secname = "based";
4477 break;
4478 case 1:
4479 secname = "tiny";
4480 break;
4481 case 2:
4482 secname = "far";
4483 break;
4484 default:
4485 ;
4486 }
4487 }
4488 }
4489 else
4490 {
4491 if (size <= mep_based_cutoff && size > 0)
4492 secname = "based";
4493 else if (size <= mep_tiny_cutoff && size > 0)
4494 secname = "tiny";
4495 else if (TARGET_L)
4496 secname = "far";
4497 }
4498
4499 if (mep_const_section && TREE_READONLY (decl))
4500 {
4501 if (strcmp (mep_const_section, "tiny") == 0)
4502 secname = "tiny";
4503 else if (strcmp (mep_const_section, "near") == 0)
4504 return;
4505 else if (strcmp (mep_const_section, "far") == 0)
4506 secname = "far";
4507 }
4508
4509 if (!secname)
4510 return;
4511
4512 if (!mep_multiple_address_regions (*attributes, true)
4513 && !mep_multiple_address_regions (DECL_ATTRIBUTES (decl), false))
4514 {
4515 attrib = build_tree_list (get_identifier (secname), NULL_TREE);
4516
4517 /* Chain the attribute directly onto the variable's DECL_ATTRIBUTES
4518 in order to avoid the POINTER_TYPE bypasses in mep_validate_near_far
4519 and mep_validate_based_tiny. */
4520 DECL_ATTRIBUTES (decl) = chainon (DECL_ATTRIBUTES (decl), attrib);
4521 }
4522}
4523
4524static void
4525mep_encode_section_info (tree decl, rtx rtl, int first)
4526{
4527 rtx rtlname;
4528 const char *oldname;
4529 const char *secname;
4530 char encoding;
4531 char *newname;
4532 tree idp;
4533 int maxsize;
4534 tree type;
4535 tree mep_attributes;
4536
4537 if (! first)
4538 return;
4539
4540 if (TREE_CODE (decl) != VAR_DECL
4541 && TREE_CODE (decl) != FUNCTION_DECL)
4542 return;
4543
4544 rtlname = XEXP (rtl, 0);
4545 if (GET_CODE (rtlname) == SYMBOL_REF)
4546 oldname = XSTR (rtlname, 0);
4547 else if (GET_CODE (rtlname) == MEM
4548 && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
4549 oldname = XSTR (XEXP (rtlname, 0), 0);
4550 else
4551 gcc_unreachable ();
4552
4553 type = TREE_TYPE (decl);
4554 if (type == error_mark_node)
4555 return;
4556 mep_attributes = MEP_ATTRIBUTES (decl);
4557
4558 encoding = mep_attrlist_to_encoding (mep_attributes, decl);
4559
4560 if (encoding)
4561 {
4562 newname = (char *) alloca (strlen (oldname) + 4);
4563 sprintf (newname, "@%c.%s", encoding, oldname);
4564 idp = get_identifier (newname);
4565 XEXP (rtl, 0) =
4566 gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
1c6679e2
NC
4567 SYMBOL_REF_WEAK (XEXP (rtl, 0)) = DECL_WEAK (decl);
4568 SET_SYMBOL_REF_DECL (XEXP (rtl, 0), decl);
7acf4da6
DD
4569
4570 switch (encoding)
4571 {
4572 case 'b':
4573 maxsize = 128;
4574 secname = "based";
4575 break;
4576 case 't':
4577 maxsize = 65536;
4578 secname = "tiny";
4579 break;
4580 case 'n':
4581 maxsize = 0x1000000;
4582 secname = "near";
4583 break;
4584 default:
4585 maxsize = 0;
4586 secname = 0;
4587 break;
4588 }
4589 if (maxsize && int_size_in_bytes (TREE_TYPE (decl)) > maxsize)
4590 {
4591 warning (0, "variable %s (%ld bytes) is too large for the %s section (%d bytes)",
4592 oldname,
4593 (long) int_size_in_bytes (TREE_TYPE (decl)),
4594 secname,
4595 maxsize);
4596 }
4597 }
7acf4da6
DD
4598}
4599
4600const char *
4601mep_strip_name_encoding (const char *sym)
4602{
4603 while (1)
4604 {
4605 if (*sym == '*')
4606 sym++;
4607 else if (*sym == '@' && sym[2] == '.')
4608 sym += 3;
4609 else
4610 return sym;
4611 }
4612}
4613
4614static section *
4615mep_select_section (tree decl, int reloc ATTRIBUTE_UNUSED,
4616 unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
4617{
4618 int readonly = 1;
820ca276 4619 int encoding;
7acf4da6
DD
4620
4621 switch (TREE_CODE (decl))
4622 {
4623 case VAR_DECL:
4624 if (!TREE_READONLY (decl)
4625 || TREE_SIDE_EFFECTS (decl)
4626 || !DECL_INITIAL (decl)
4627 || (DECL_INITIAL (decl) != error_mark_node
4628 && !TREE_CONSTANT (DECL_INITIAL (decl))))
4629 readonly = 0;
4630 break;
4631 case CONSTRUCTOR:
4632 if (! TREE_CONSTANT (decl))
4633 readonly = 0;
4634 break;
4635
4636 default:
4637 break;
4638 }
4639
820ca276
DD
4640 if (TREE_CODE (decl) == FUNCTION_DECL)
4641 {
4642 const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
4643
4644 if (name[0] == '@' && name[2] == '.')
4645 encoding = name[1];
4646 else
4647 encoding = 0;
4648
4649 if (flag_function_sections || DECL_ONE_ONLY (decl))
4650 mep_unique_section (decl, 0);
4651 else if (lookup_attribute ("vliw", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
4652 {
4653 if (encoding == 'f')
4654 return vftext_section;
4655 else
4656 return vtext_section;
4657 }
4658 else if (encoding == 'f')
4659 return ftext_section;
4660 else
4661 return text_section;
4662 }
4663
7acf4da6
DD
4664 if (TREE_CODE (decl) == VAR_DECL)
4665 {
4666 const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
4667
4668 if (name[0] == '@' && name[2] == '.')
4669 switch (name[1])
4670 {
4671 case 'b':
4672 return based_section;
4673
4674 case 't':
4675 if (readonly)
4676 return srodata_section;
4677 if (DECL_INITIAL (decl))
4678 return sdata_section;
4679 return tinybss_section;
4680
4681 case 'f':
4682 if (readonly)
4683 return frodata_section;
4684 return far_section;
4685
4686 case 'i':
4687 case 'I':
dcb91ebe
MLI
4688 error_at (DECL_SOURCE_LOCATION (decl),
4689 "variable %D of type %<io%> must be uninitialized", decl);
7acf4da6
DD
4690 return data_section;
4691
4692 case 'c':
dcb91ebe
MLI
4693 error_at (DECL_SOURCE_LOCATION (decl),
4694 "variable %D of type %<cb%> must be uninitialized", decl);
7acf4da6
DD
4695 return data_section;
4696 }
4697 }
4698
4699 if (readonly)
4700 return readonly_data_section;
4701
4702 return data_section;
4703}
4704
4705static void
4706mep_unique_section (tree decl, int reloc)
4707{
4708 static const char *prefixes[][2] =
4709 {
4710 { ".text.", ".gnu.linkonce.t." },
4711 { ".rodata.", ".gnu.linkonce.r." },
4712 { ".data.", ".gnu.linkonce.d." },
4713 { ".based.", ".gnu.linkonce.based." },
4714 { ".sdata.", ".gnu.linkonce.s." },
4715 { ".far.", ".gnu.linkonce.far." },
4716 { ".ftext.", ".gnu.linkonce.ft." },
4717 { ".frodata.", ".gnu.linkonce.frd." },
820ca276
DD
4718 { ".srodata.", ".gnu.linkonce.srd." },
4719 { ".vtext.", ".gnu.linkonce.v." },
4720 { ".vftext.", ".gnu.linkonce.vf." }
7acf4da6
DD
4721 };
4722 int sec = 2; /* .data */
4723 int len;
4724 const char *name, *prefix;
4725 char *string;
4726
4727 name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
4728 if (DECL_RTL (decl))
4729 name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
4730
4731 if (TREE_CODE (decl) == FUNCTION_DECL)
820ca276
DD
4732 {
4733 if (lookup_attribute ("vliw", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
4734 sec = 9; /* .vtext */
4735 else
4736 sec = 0; /* .text */
4737 }
7acf4da6
DD
4738 else if (decl_readonly_section (decl, reloc))
4739 sec = 1; /* .rodata */
4740
4741 if (name[0] == '@' && name[2] == '.')
4742 {
4743 switch (name[1])
4744 {
4745 case 'b':
4746 sec = 3; /* .based */
4747 break;
4748 case 't':
4749 if (sec == 1)
4750 sec = 8; /* .srodata */
4751 else
4752 sec = 4; /* .sdata */
4753 break;
4754 case 'f':
4755 if (sec == 0)
4756 sec = 6; /* .ftext */
820ca276
DD
4757 else if (sec == 9)
4758 sec = 10; /* .vftext */
7acf4da6
DD
4759 else if (sec == 1)
4760 sec = 7; /* .frodata */
4761 else
4762 sec = 5; /* .far. */
4763 break;
4764 }
4765 name += 3;
4766 }
4767
4768 prefix = prefixes[sec][DECL_ONE_ONLY(decl)];
4769 len = strlen (name) + strlen (prefix);
4770 string = (char *) alloca (len + 1);
4771
4772 sprintf (string, "%s%s", prefix, name);
4773
4774 DECL_SECTION_NAME (decl) = build_string (len, string);
4775}
4776
4777/* Given a decl, a section name, and whether the decl initializer
4778 has relocs, choose attributes for the section. */
4779
4780#define SECTION_MEP_VLIW SECTION_MACH_DEP
4781
4782static unsigned int
4783mep_section_type_flags (tree decl, const char *name, int reloc)
4784{
4785 unsigned int flags = default_section_type_flags (decl, name, reloc);
4786
4787 if (decl && TREE_CODE (decl) == FUNCTION_DECL
4788 && lookup_attribute ("vliw", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
4789 flags |= SECTION_MEP_VLIW;
4790
4791 return flags;
4792}
4793
4794/* Switch to an arbitrary section NAME with attributes as specified
4795 by FLAGS. ALIGN specifies any known alignment requirements for
4796 the section; 0 if the default should be used.
4797
4798 Differs from the standard ELF version only in support of VLIW mode. */
4799
4800static void
4801mep_asm_named_section (const char *name, unsigned int flags, tree decl ATTRIBUTE_UNUSED)
4802{
4803 char flagchars[8], *f = flagchars;
4804 const char *type;
4805
4806 if (!(flags & SECTION_DEBUG))
4807 *f++ = 'a';
4808 if (flags & SECTION_WRITE)
4809 *f++ = 'w';
4810 if (flags & SECTION_CODE)
4811 *f++ = 'x';
4812 if (flags & SECTION_SMALL)
4813 *f++ = 's';
4814 if (flags & SECTION_MEP_VLIW)
4815 *f++ = 'v';
4816 *f = '\0';
4817
4818 if (flags & SECTION_BSS)
4819 type = "nobits";
4820 else
4821 type = "progbits";
4822
4823 fprintf (asm_out_file, "\t.section\t%s,\"%s\",@%s\n",
4824 name, flagchars, type);
4825
4826 if (flags & SECTION_CODE)
4827 fputs ((flags & SECTION_MEP_VLIW ? "\t.vliw\n" : "\t.core\n"),
4828 asm_out_file);
4829}
4830
4831void
4832mep_output_aligned_common (FILE *stream, tree decl, const char *name,
4833 int size, int align, int global)
4834{
4835 /* We intentionally don't use mep_section_tag() here. */
4836 if (name[0] == '@'
4837 && (name[1] == 'i' || name[1] == 'I' || name[1] == 'c')
4838 && name[2] == '.')
4839 {
4840 int location = -1;
4841 tree attr = lookup_attribute ((name[1] == 'c' ? "cb" : "io"),
4842 DECL_ATTRIBUTES (decl));
4843 if (attr
4844 && TREE_VALUE (attr)
4845 && TREE_VALUE (TREE_VALUE(attr)))
4846 location = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE(attr)));
4847 if (location == -1)
4848 return;
4849 if (global)
4850 {
4851 fprintf (stream, "\t.globl\t");
4852 assemble_name (stream, name);
4853 fprintf (stream, "\n");
4854 }
4855 assemble_name (stream, name);
4856 fprintf (stream, " = %d\n", location);
4857 return;
4858 }
4859 if (name[0] == '@' && name[2] == '.')
4860 {
4861 const char *sec = 0;
4862 switch (name[1])
4863 {
4864 case 'b':
4865 switch_to_section (based_section);
4866 sec = ".based";
4867 break;
4868 case 't':
4869 switch_to_section (tinybss_section);
4870 sec = ".sbss";
4871 break;
4872 case 'f':
4873 switch_to_section (farbss_section);
4874 sec = ".farbss";
4875 break;
4876 }
4877 if (sec)
4878 {
4879 const char *name2;
4880 int p2align = 0;
4881
4882 while (align > BITS_PER_UNIT)
4883 {
4884 align /= 2;
4885 p2align ++;
4886 }
4887 name2 = TARGET_STRIP_NAME_ENCODING (name);
4888 if (global)
4889 fprintf (stream, "\t.globl\t%s\n", name2);
4890 fprintf (stream, "\t.p2align %d\n", p2align);
4891 fprintf (stream, "\t.type\t%s,@object\n", name2);
4892 fprintf (stream, "\t.size\t%s,%d\n", name2, size);
4893 fprintf (stream, "%s:\n\t.zero\t%d\n", name2, size);
4894 return;
4895 }
4896 }
4897
4898 if (!global)
4899 {
4900 fprintf (stream, "\t.local\t");
4901 assemble_name (stream, name);
4902 fprintf (stream, "\n");
4903 }
4904 fprintf (stream, "\t.comm\t");
4905 assemble_name (stream, name);
4906 fprintf (stream, ",%u,%u\n", size, align / BITS_PER_UNIT);
4907}
4908
4909/* Trampolines. */
4910
4911void
4912mep_init_trampoline (rtx addr, rtx fnaddr, rtx static_chain)
4913{
4914 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__mep_trampoline_helper"),
4915 LCT_NORMAL, VOIDmode, 3,
4916 addr, Pmode,
4917 fnaddr, Pmode,
4918 static_chain, Pmode);
4919}
4920
4921/* Experimental Reorg. */
4922
4923static bool
4924mep_mentioned_p (rtx in,
4925 rtx reg, /* NULL for mem */
4926 int modes_too) /* if nonzero, modes must match also. */
4927{
4928 const char *fmt;
4929 int i;
4930 enum rtx_code code;
4931
4932 if (in == 0)
4933 return false;
4934 if (reg && GET_CODE (reg) != REG)
4935 return false;
4936
4937 if (GET_CODE (in) == LABEL_REF)
4938 return (reg == 0);
4939
4940 code = GET_CODE (in);
4941
4942 switch (code)
4943 {
4944 case MEM:
4945 if (reg)
4946 return mep_mentioned_p (XEXP (in, 0), reg, modes_too);
4947 return true;
4948
4949 case REG:
4950 if (!reg)
4951 return false;
4952 if (modes_too && (GET_MODE (in) != GET_MODE (reg)))
4953 return false;
4954 return (REGNO (in) == REGNO (reg));
4955
4956 case SCRATCH:
4957 case CC0:
4958 case PC:
4959 case CONST_INT:
4960 case CONST_DOUBLE:
4961 return false;
4962
4963 default:
4964 break;
4965 }
4966
4967 /* Set's source should be read-only. */
4968 if (code == SET && !reg)
4969 return mep_mentioned_p (SET_DEST (in), reg, modes_too);
4970
4971 fmt = GET_RTX_FORMAT (code);
4972
4973 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
4974 {
4975 if (fmt[i] == 'E')
4976 {
4977 register int j;
4978 for (j = XVECLEN (in, i) - 1; j >= 0; j--)
4979 if (mep_mentioned_p (XVECEXP (in, i, j), reg, modes_too))
4980 return true;
4981 }
4982 else if (fmt[i] == 'e'
4983 && mep_mentioned_p (XEXP (in, i), reg, modes_too))
4984 return true;
4985 }
4986 return false;
4987}
4988
4989#define EXPERIMENTAL_REGMOVE_REORG 1
4990
4991#if EXPERIMENTAL_REGMOVE_REORG
4992
4993static int
4994mep_compatible_reg_class (int r1, int r2)
4995{
4996 if (GR_REGNO_P (r1) && GR_REGNO_P (r2))
4997 return 1;
4998 if (CR_REGNO_P (r1) && CR_REGNO_P (r2))
4999 return 1;
5000 return 0;
5001}
5002
5003static void
5004mep_reorg_regmove (rtx insns)
5005{
5006 rtx insn, next, pat, follow, *where;
5007 int count = 0, done = 0, replace, before = 0;
5008
5009 if (dump_file)
5010 for (insn = insns; insn; insn = NEXT_INSN (insn))
5011 if (GET_CODE (insn) == INSN)
5012 before++;
5013
5014 /* We're looking for (set r2 r1) moves where r1 dies, followed by a
5015 set that uses the r2 and r2 dies there. We replace r2 with r1
5016 and see if it's still a valid insn. If so, delete the first set.
5017 Copied from reorg.c. */
5018
5019 while (!done)
5020 {
5021 done = 1;
5022 for (insn = insns; insn; insn = next)
5023 {
5024 next = NEXT_INSN (insn);
5025 if (GET_CODE (insn) != INSN)
5026 continue;
5027 pat = PATTERN (insn);
5028
5029 replace = 0;
5030
5031 if (GET_CODE (pat) == SET
5032 && GET_CODE (SET_SRC (pat)) == REG
5033 && GET_CODE (SET_DEST (pat)) == REG
5034 && find_regno_note (insn, REG_DEAD, REGNO (SET_SRC (pat)))
5035 && mep_compatible_reg_class (REGNO (SET_SRC (pat)), REGNO (SET_DEST (pat))))
5036 {
5037 follow = next_nonnote_insn (insn);
5038 if (dump_file)
5039 fprintf (dump_file, "superfluous moves: considering %d\n", INSN_UID (insn));
5040
5041 while (follow && GET_CODE (follow) == INSN
5042 && GET_CODE (PATTERN (follow)) == SET
5043 && !dead_or_set_p (follow, SET_SRC (pat))
5044 && !mep_mentioned_p (PATTERN (follow), SET_SRC (pat), 0)
5045 && !mep_mentioned_p (PATTERN (follow), SET_DEST (pat), 0))
5046 {
5047 if (dump_file)
5048 fprintf (dump_file, "\tskipping %d\n", INSN_UID (follow));
5049 follow = next_nonnote_insn (follow);
5050 }
5051
5052 if (dump_file)
5053 fprintf (dump_file, "\tfollow is %d\n", INSN_UID (follow));
5054 if (follow && GET_CODE (follow) == INSN
5055 && GET_CODE (PATTERN (follow)) == SET
5056 && find_regno_note (follow, REG_DEAD, REGNO (SET_DEST (pat))))
5057 {
5058 if (GET_CODE (SET_DEST (PATTERN (follow))) == REG)
5059 {
5060 if (mep_mentioned_p (SET_SRC (PATTERN (follow)), SET_DEST (pat), 1))
5061 {
5062 replace = 1;
5063 where = & SET_SRC (PATTERN (follow));
5064 }
5065 }
5066 else if (GET_CODE (SET_DEST (PATTERN (follow))) == MEM)
5067 {
5068 if (mep_mentioned_p (PATTERN (follow), SET_DEST (pat), 1))
5069 {
5070 replace = 1;
5071 where = & PATTERN (follow);
5072 }
5073 }
5074 }
5075 }
5076
5077 /* If so, follow is the corresponding insn */
5078 if (replace)
5079 {
5080 if (dump_file)
5081 {
5082 rtx x;
5083
5084 fprintf (dump_file, "----- Candidate for superfluous move deletion:\n\n");
5085 for (x = insn; x ;x = NEXT_INSN (x))
5086 {
5087 print_rtl_single (dump_file, x);
5088 if (x == follow)
5089 break;
5090 fprintf (dump_file, "\n");
5091 }
5092 }
5093
5094 if (validate_replace_rtx_subexp (SET_DEST (pat), SET_SRC (pat),
5095 follow, where))
5096 {
5097 count ++;
5098 next = delete_insn (insn);
5099 if (dump_file)
5100 {
5101 fprintf (dump_file, "\n----- Success! new insn:\n\n");
5102 print_rtl_single (dump_file, follow);
5103 }
5104 done = 0;
5105 }
5106 }
5107 }
5108 }
5109
5110 if (dump_file)
5111 {
5112 fprintf (dump_file, "\n%d insn%s deleted out of %d.\n\n", count, count == 1 ? "" : "s", before);
5113 fprintf (dump_file, "=====\n");
5114 }
5115}
5116#endif
5117
5118
5119/* Figure out where to put LABEL, which is the label for a repeat loop.
5120 If INCLUDING, LAST_INSN is the last instruction in the loop, otherwise
5121 the loop ends just before LAST_INSN. If SHARED, insns other than the
5122 "repeat" might use LABEL to jump to the loop's continuation point.
5123
5124 Return the last instruction in the adjusted loop. */
5125
5126static rtx
5127mep_insert_repeat_label_last (rtx last_insn, rtx label, bool including,
5128 bool shared)
5129{
5130 rtx next, prev;
5131 int count = 0, code, icode;
5132
5133 if (dump_file)
5134 fprintf (dump_file, "considering end of repeat loop at insn %d\n",
5135 INSN_UID (last_insn));
5136
5137 /* Set PREV to the last insn in the loop. */
5138 prev = last_insn;
5139 if (!including)
5140 prev = PREV_INSN (prev);
5141
5142 /* Set NEXT to the next insn after the repeat label. */
5143 next = last_insn;
5144 if (!shared)
5145 while (prev != 0)
5146 {
5147 code = GET_CODE (prev);
5148 if (code == CALL_INSN || code == CODE_LABEL || code == BARRIER)
5149 break;
5150
5151 if (INSN_P (prev))
5152 {
5153 if (GET_CODE (PATTERN (prev)) == SEQUENCE)
5154 prev = XVECEXP (PATTERN (prev), 0, 1);
5155
5156 /* Other insns that should not be in the last two opcodes. */
5157 icode = recog_memoized (prev);
5158 if (icode < 0
5159 || icode == CODE_FOR_repeat
5160 || icode == CODE_FOR_erepeat
5161 || get_attr_may_trap (prev) == MAY_TRAP_YES)
5162 break;
5163
5164 /* That leaves JUMP_INSN and INSN. It will have BImode if it
5165 is the second instruction in a VLIW bundle. In that case,
5166 loop again: if the first instruction also satisfies the
5167 conditions above then we will reach here again and put
5168 both of them into the repeat epilogue. Otherwise both
5169 should remain outside. */
5170 if (GET_MODE (prev) != BImode)
5171 {
5172 count++;
5173 next = prev;
5174 if (dump_file)
5175 print_rtl_single (dump_file, next);
5176 if (count == 2)
5177 break;
5178 }
5179 }
5180 prev = PREV_INSN (prev);
5181 }
5182
5183 /* See if we're adding the label immediately after the repeat insn.
5184 If so, we need to separate them with a nop. */
5185 prev = prev_real_insn (next);
5186 if (prev)
5187 switch (recog_memoized (prev))
5188 {
5189 case CODE_FOR_repeat:
5190 case CODE_FOR_erepeat:
5191 if (dump_file)
5192 fprintf (dump_file, "Adding nop inside loop\n");
5193 emit_insn_before (gen_nop (), next);
5194 break;
5195
5196 default:
5197 break;
5198 }
5199
5200 /* Insert the label. */
5201 emit_label_before (label, next);
5202
5203 /* Insert the nops. */
5204 if (dump_file && count < 2)
5205 fprintf (dump_file, "Adding %d nop%s\n\n",
5206 2 - count, count == 1 ? "" : "s");
5207
5208 for (; count < 2; count++)
5209 if (including)
5210 last_insn = emit_insn_after (gen_nop (), last_insn);
5211 else
5212 emit_insn_before (gen_nop (), last_insn);
5213
5214 return last_insn;
5215}
5216
5217
5218void
5219mep_emit_doloop (rtx *operands, int is_end)
5220{
5221 rtx tag;
5222
5223 if (cfun->machine->doloop_tags == 0
5224 || cfun->machine->doloop_tag_from_end == is_end)
5225 {
5226 cfun->machine->doloop_tags++;
5227 cfun->machine->doloop_tag_from_end = is_end;
5228 }
5229
5230 tag = GEN_INT (cfun->machine->doloop_tags - 1);
5231 if (is_end)
5232 emit_jump_insn (gen_doloop_end_internal (operands[0], operands[4], tag));
5233 else
5234 emit_insn (gen_doloop_begin_internal (operands[0], operands[0], tag));
5235}
5236
5237
5238/* Code for converting doloop_begins and doloop_ends into valid
5239 MeP instructions. A doloop_begin is just a placeholder:
5240
5241 $count = unspec ($count)
5242
5243 where $count is initially the number of iterations - 1.
5244 doloop_end has the form:
5245
5246 if ($count-- == 0) goto label
5247
5248 The counter variable is private to the doloop insns, nothing else
5249 relies on its value.
5250
5251 There are three cases, in decreasing order of preference:
5252
5253 1. A loop has exactly one doloop_begin and one doloop_end.
5254 The doloop_end branches to the first instruction after
5255 the doloop_begin.
5256
5257 In this case we can replace the doloop_begin with a repeat
5258 instruction and remove the doloop_end. I.e.:
5259
5260 $count1 = unspec ($count1)
5261 label:
5262 ...
5263 insn1
5264 insn2
5265 if ($count2-- == 0) goto label
5266
5267 becomes:
5268
5269 repeat $count1,repeat_label
5270 label:
5271 ...
5272 repeat_label:
5273 insn1
5274 insn2
5275 # end repeat
5276
5277 2. As for (1), except there are several doloop_ends. One of them
5278 (call it X) falls through to a label L. All the others fall
5279 through to branches to L.
5280
5281 In this case, we remove X and replace the other doloop_ends
5282 with branches to the repeat label. For example:
5283
5284 $count1 = unspec ($count1)
5285 start:
5286 ...
5287 if ($count2-- == 0) goto label
5288 end:
5289 ...
5290 if ($count3-- == 0) goto label
5291 goto end
5292
5293 becomes:
5294
5295 repeat $count1,repeat_label
5296 start:
5297 ...
5298 repeat_label:
5299 nop
5300 nop
5301 # end repeat
5302 end:
5303 ...
5304 goto repeat_label
5305
5306 3. The fallback case. Replace doloop_begins with:
5307
5308 $count = $count + 1
5309
5310 Replace doloop_ends with the equivalent of:
5311
5312 $count = $count - 1
5313 if ($count == 0) goto label
5314
5315 Note that this might need a scratch register if $count
5316 is stored in memory. */
5317
5318/* A structure describing one doloop_begin. */
5319struct mep_doloop_begin {
5320 /* The next doloop_begin with the same tag. */
5321 struct mep_doloop_begin *next;
5322
5323 /* The instruction itself. */
5324 rtx insn;
5325
5326 /* The initial counter value. This is known to be a general register. */
5327 rtx counter;
5328};
5329
5330/* A structure describing a doloop_end. */
5331struct mep_doloop_end {
5332 /* The next doloop_end with the same loop tag. */
5333 struct mep_doloop_end *next;
5334
5335 /* The instruction itself. */
5336 rtx insn;
5337
5338 /* The first instruction after INSN when the branch isn't taken. */
5339 rtx fallthrough;
5340
5341 /* The location of the counter value. Since doloop_end_internal is a
5342 jump instruction, it has to allow the counter to be stored anywhere
5343 (any non-fixed register or memory location). */
5344 rtx counter;
5345
5346 /* The target label (the place where the insn branches when the counter
5347 isn't zero). */
5348 rtx label;
5349
5350 /* A scratch register. Only available when COUNTER isn't stored
5351 in a general register. */
5352 rtx scratch;
5353};
5354
5355
5356/* One do-while loop. */
5357struct mep_doloop {
5358 /* All the doloop_begins for this loop (in no particular order). */
5359 struct mep_doloop_begin *begin;
5360
5361 /* All the doloop_ends. When there is more than one, arrange things
5362 so that the first one is the most likely to be X in case (2) above. */
5363 struct mep_doloop_end *end;
5364};
5365
5366
5367/* Return true if LOOP can be converted into repeat/repeat_end form
5368 (that is, if it matches cases (1) or (2) above). */
5369
5370static bool
5371mep_repeat_loop_p (struct mep_doloop *loop)
5372{
5373 struct mep_doloop_end *end;
5374 rtx fallthrough;
5375
5376 /* There must be exactly one doloop_begin and at least one doloop_end. */
5377 if (loop->begin == 0 || loop->end == 0 || loop->begin->next != 0)
5378 return false;
5379
5380 /* The first doloop_end (X) must branch back to the insn after
5381 the doloop_begin. */
5382 if (prev_real_insn (loop->end->label) != loop->begin->insn)
5383 return false;
5384
5385 /* All the other doloop_ends must branch to the same place as X.
5386 When the branch isn't taken, they must jump to the instruction
5387 after X. */
5388 fallthrough = loop->end->fallthrough;
5389 for (end = loop->end->next; end != 0; end = end->next)
5390 if (end->label != loop->end->label
5391 || !simplejump_p (end->fallthrough)
5392 || next_real_insn (JUMP_LABEL (end->fallthrough)) != fallthrough)
5393 return false;
5394
5395 return true;
5396}
5397
5398
5399/* The main repeat reorg function. See comment above for details. */
5400
5401static void
5402mep_reorg_repeat (rtx insns)
5403{
5404 rtx insn;
5405 struct mep_doloop *loops, *loop;
5406 struct mep_doloop_begin *begin;
5407 struct mep_doloop_end *end;
5408
5409 /* Quick exit if we haven't created any loops. */
5410 if (cfun->machine->doloop_tags == 0)
5411 return;
5412
5413 /* Create an array of mep_doloop structures. */
5414 loops = (struct mep_doloop *) alloca (sizeof (loops[0]) * cfun->machine->doloop_tags);
5415 memset (loops, 0, sizeof (loops[0]) * cfun->machine->doloop_tags);
5416
5417 /* Search the function for do-while insns and group them by loop tag. */
5418 for (insn = insns; insn; insn = NEXT_INSN (insn))
5419 if (INSN_P (insn))
5420 switch (recog_memoized (insn))
5421 {
5422 case CODE_FOR_doloop_begin_internal:
5423 insn_extract (insn);
5424 loop = &loops[INTVAL (recog_data.operand[2])];
5425
5426 begin = (struct mep_doloop_begin *) alloca (sizeof (struct mep_doloop_begin));
5427 begin->next = loop->begin;
5428 begin->insn = insn;
5429 begin->counter = recog_data.operand[0];
5430
5431 loop->begin = begin;
5432 break;
5433
5434 case CODE_FOR_doloop_end_internal:
5435 insn_extract (insn);
5436 loop = &loops[INTVAL (recog_data.operand[2])];
5437
5438 end = (struct mep_doloop_end *) alloca (sizeof (struct mep_doloop_end));
5439 end->insn = insn;
5440 end->fallthrough = next_real_insn (insn);
5441 end->counter = recog_data.operand[0];
5442 end->label = recog_data.operand[1];
5443 end->scratch = recog_data.operand[3];
5444
5445 /* If this insn falls through to an unconditional jump,
5446 give it a lower priority than the others. */
5447 if (loop->end != 0 && simplejump_p (end->fallthrough))
5448 {
5449 end->next = loop->end->next;
5450 loop->end->next = end;
5451 }
5452 else
5453 {
5454 end->next = loop->end;
5455 loop->end = end;
5456 }
5457 break;
5458 }
5459
5460 /* Convert the insns for each loop in turn. */
5461 for (loop = loops; loop < loops + cfun->machine->doloop_tags; loop++)
5462 if (mep_repeat_loop_p (loop))
5463 {
5464 /* Case (1) or (2). */
5465 rtx repeat_label, label_ref;
5466
5467 /* Create a new label for the repeat insn. */
5468 repeat_label = gen_label_rtx ();
5469
5470 /* Replace the doloop_begin with a repeat. */
5471 label_ref = gen_rtx_LABEL_REF (VOIDmode, repeat_label);
5472 emit_insn_before (gen_repeat (loop->begin->counter, label_ref),
5473 loop->begin->insn);
5474 delete_insn (loop->begin->insn);
5475
5476 /* Insert the repeat label before the first doloop_end.
5477 Fill the gap with nops if there are other doloop_ends. */
5478 mep_insert_repeat_label_last (loop->end->insn, repeat_label,
5479 false, loop->end->next != 0);
5480
5481 /* Emit a repeat_end (to improve the readability of the output). */
5482 emit_insn_before (gen_repeat_end (), loop->end->insn);
5483
5484 /* Delete the first doloop_end. */
5485 delete_insn (loop->end->insn);
5486
5487 /* Replace the others with branches to REPEAT_LABEL. */
5488 for (end = loop->end->next; end != 0; end = end->next)
5489 {
5490 emit_jump_insn_before (gen_jump (repeat_label), end->insn);
5491 delete_insn (end->insn);
5492 delete_insn (end->fallthrough);
5493 }
5494 }
5495 else
5496 {
5497 /* Case (3). First replace all the doloop_begins with increment
5498 instructions. */
5499 for (begin = loop->begin; begin != 0; begin = begin->next)
5500 {
5501 emit_insn_before (gen_add3_insn (copy_rtx (begin->counter),
5502 begin->counter, const1_rtx),
5503 begin->insn);
5504 delete_insn (begin->insn);
5505 }
5506
5507 /* Replace all the doloop_ends with decrement-and-branch sequences. */
5508 for (end = loop->end; end != 0; end = end->next)
5509 {
5510 rtx reg;
5511
5512 start_sequence ();
5513
5514 /* Load the counter value into a general register. */
5515 reg = end->counter;
5516 if (!REG_P (reg) || REGNO (reg) > 15)
5517 {
5518 reg = end->scratch;
5519 emit_move_insn (copy_rtx (reg), copy_rtx (end->counter));
5520 }
5521
5522 /* Decrement the counter. */
5523 emit_insn (gen_add3_insn (copy_rtx (reg), copy_rtx (reg),
5524 constm1_rtx));
5525
5526 /* Copy it back to its original location. */
5527 if (reg != end->counter)
5528 emit_move_insn (copy_rtx (end->counter), copy_rtx (reg));
5529
5530 /* Jump back to the start label. */
5531 insn = emit_jump_insn (gen_mep_bne_true (reg, const0_rtx,
5532 end->label));
5533 JUMP_LABEL (insn) = end->label;
5534 LABEL_NUSES (end->label)++;
5535
5536 /* Emit the whole sequence before the doloop_end. */
5537 insn = get_insns ();
5538 end_sequence ();
5539 emit_insn_before (insn, end->insn);
5540
5541 /* Delete the doloop_end. */
5542 delete_insn (end->insn);
5543 }
5544 }
5545}
5546
5547
5548static bool
5549mep_invertable_branch_p (rtx insn)
5550{
5551 rtx cond, set;
5552 enum rtx_code old_code;
5553 int i;
5554
5555 set = PATTERN (insn);
5556 if (GET_CODE (set) != SET)
5557 return false;
5558 if (GET_CODE (XEXP (set, 1)) != IF_THEN_ELSE)
5559 return false;
5560 cond = XEXP (XEXP (set, 1), 0);
5561 old_code = GET_CODE (cond);
5562 switch (old_code)
5563 {
5564 case EQ:
5565 PUT_CODE (cond, NE);
5566 break;
5567 case NE:
5568 PUT_CODE (cond, EQ);
5569 break;
5570 case LT:
5571 PUT_CODE (cond, GE);
5572 break;
5573 case GE:
5574 PUT_CODE (cond, LT);
5575 break;
5576 default:
5577 return false;
5578 }
5579 INSN_CODE (insn) = -1;
5580 i = recog_memoized (insn);
5581 PUT_CODE (cond, old_code);
5582 INSN_CODE (insn) = -1;
5583 return i >= 0;
5584}
5585
5586static void
5587mep_invert_branch (rtx insn, rtx after)
5588{
5589 rtx cond, set, label;
5590 int i;
5591
5592 set = PATTERN (insn);
5593
5594 gcc_assert (GET_CODE (set) == SET);
5595 gcc_assert (GET_CODE (XEXP (set, 1)) == IF_THEN_ELSE);
5596
5597 cond = XEXP (XEXP (set, 1), 0);
5598 switch (GET_CODE (cond))
5599 {
5600 case EQ:
5601 PUT_CODE (cond, NE);
5602 break;
5603 case NE:
5604 PUT_CODE (cond, EQ);
5605 break;
5606 case LT:
5607 PUT_CODE (cond, GE);
5608 break;
5609 case GE:
5610 PUT_CODE (cond, LT);
5611 break;
5612 default:
5613 gcc_unreachable ();
5614 }
5615 label = gen_label_rtx ();
5616 emit_label_after (label, after);
5617 for (i=1; i<=2; i++)
5618 if (GET_CODE (XEXP (XEXP (set, 1), i)) == LABEL_REF)
5619 {
5620 rtx ref = XEXP (XEXP (set, 1), i);
5621 if (LABEL_NUSES (XEXP (ref, 0)) == 1)
5622 delete_insn (XEXP (ref, 0));
5623 XEXP (ref, 0) = label;
5624 LABEL_NUSES (label) ++;
5625 JUMP_LABEL (insn) = label;
5626 }
5627 INSN_CODE (insn) = -1;
5628 i = recog_memoized (insn);
5629 gcc_assert (i >= 0);
5630}
5631
5632static void
5633mep_reorg_erepeat (rtx insns)
5634{
5635 rtx insn, prev, label_before, l, x;
5636 int count;
5637
5638 for (insn = insns; insn; insn = NEXT_INSN (insn))
5639 if (JUMP_P (insn)
5640 && ! JUMP_TABLE_DATA_P (insn)
5641 && mep_invertable_branch_p (insn))
5642 {
5643 if (dump_file)
5644 {
5645 fprintf (dump_file, "\n------------------------------\n");
5646 fprintf (dump_file, "erepeat: considering this jump:\n");
5647 print_rtl_single (dump_file, insn);
5648 }
5649 count = simplejump_p (insn) ? 0 : 1;
5650 label_before = 0;
5651 for (prev = PREV_INSN (insn); prev; prev = PREV_INSN (prev))
5652 {
5653 if (GET_CODE (prev) == CALL_INSN
5654 || BARRIER_P (prev))
5655 break;
5656
5657 if (prev == JUMP_LABEL (insn))
5658 {
5659 rtx newlast;
5660 if (dump_file)
5661 fprintf (dump_file, "found loop top, %d insns\n", count);
5662
5663 if (LABEL_NUSES (prev) == 1)
5664 /* We're the only user, always safe */ ;
5665 else if (LABEL_NUSES (prev) == 2)
5666 {
5667 /* See if there's a barrier before this label. If
5668 so, we know nobody inside the loop uses it.
5669 But we must be careful to put the erepeat
5670 *after* the label. */
5671 rtx barrier;
5672 for (barrier = PREV_INSN (prev);
5673 barrier && GET_CODE (barrier) == NOTE;
5674 barrier = PREV_INSN (barrier))
5675 ;
5676 if (barrier && GET_CODE (barrier) != BARRIER)
5677 break;
5678 }
5679 else
5680 {
5681 /* We don't know who else, within or without our loop, uses this */
5682 if (dump_file)
5683 fprintf (dump_file, "... but there are multiple users, too risky.\n");
5684 break;
5685 }
5686
5687 /* Generate a label to be used by the erepat insn. */
5688 l = gen_label_rtx ();
5689
5690 /* Insert the erepeat after INSN's target label. */
5691 x = gen_erepeat (gen_rtx_LABEL_REF (VOIDmode, l));
5692 LABEL_NUSES (l)++;
5693 emit_insn_after (x, prev);
5694
5695 /* Insert the erepeat label. */
5696 newlast = (mep_insert_repeat_label_last
5697 (insn, l, !simplejump_p (insn), false));
5698 if (simplejump_p (insn))
5699 {
5700 emit_insn_before (gen_erepeat_end (), insn);
5701 delete_insn (insn);
5702 }
5703 else
5704 {
5705 mep_invert_branch (insn, newlast);
5706 emit_insn_after (gen_erepeat_end (), newlast);
5707 }
5708 break;
5709 }
5710
5711 if (LABEL_P (prev))
5712 {
5713 /* A label is OK if there is exactly one user, and we
5714 can find that user before the next label. */
5715 rtx user = 0;
5716 int safe = 0;
5717 if (LABEL_NUSES (prev) == 1)
5718 {
5719 for (user = PREV_INSN (prev);
5720 user && (INSN_P (user) || GET_CODE (user) == NOTE);
5721 user = PREV_INSN (user))
5722 if (GET_CODE (user) == JUMP_INSN
5723 && JUMP_LABEL (user) == prev)
5724 {
5725 safe = INSN_UID (user);
5726 break;
5727 }
5728 }
5729 if (!safe)
5730 break;
5731 if (dump_file)
5732 fprintf (dump_file, "... ignoring jump from insn %d to %d\n",
5733 safe, INSN_UID (prev));
5734 }
5735
5736 if (INSN_P (prev))
5737 {
5738 count ++;
5739 if (count == 2)
5740 label_before = prev;
5741 }
5742 }
5743 }
5744 if (dump_file)
5745 fprintf (dump_file, "\n==============================\n");
5746}
5747
5748/* Replace a jump to a return, with a copy of the return. GCC doesn't
5749 always do this on its own. */
5750
5751static void
5752mep_jmp_return_reorg (rtx insns)
5753{
5754 rtx insn, label, ret;
5755 int ret_code;
5756
5757 for (insn = insns; insn; insn = NEXT_INSN (insn))
5758 if (simplejump_p (insn))
5759 {
5760 /* Find the fist real insn the jump jumps to. */
5761 label = ret = JUMP_LABEL (insn);
5762 while (ret
5763 && (GET_CODE (ret) == NOTE
5764 || GET_CODE (ret) == CODE_LABEL
5765 || GET_CODE (PATTERN (ret)) == USE))
5766 ret = NEXT_INSN (ret);
5767
5768 if (ret)
5769 {
5770 /* Is it a return? */
5771 ret_code = recog_memoized (ret);
5772 if (ret_code == CODE_FOR_return_internal
5773 || ret_code == CODE_FOR_eh_return_internal)
5774 {
5775 /* It is. Replace the jump with a return. */
5776 LABEL_NUSES (label) --;
5777 if (LABEL_NUSES (label) == 0)
5778 delete_insn (label);
5779 PATTERN (insn) = copy_rtx (PATTERN (ret));
5780 INSN_CODE (insn) = -1;
5781 }
5782 }
5783 }
5784}
5785
5786
5787static void
5788mep_reorg_addcombine (rtx insns)
5789{
5790 rtx i, n;
5791
5792 for (i = insns; i; i = NEXT_INSN (i))
5793 if (INSN_P (i)
5794 && INSN_CODE (i) == CODE_FOR_addsi3
5795 && GET_CODE (SET_DEST (PATTERN (i))) == REG
5796 && GET_CODE (XEXP (SET_SRC (PATTERN (i)), 0)) == REG
5797 && REGNO (SET_DEST (PATTERN (i))) == REGNO (XEXP (SET_SRC (PATTERN (i)), 0))
5798 && GET_CODE (XEXP (SET_SRC (PATTERN (i)), 1)) == CONST_INT)
5799 {
5800 n = NEXT_INSN (i);
5801 if (INSN_P (n)
5802 && INSN_CODE (n) == CODE_FOR_addsi3
5803 && GET_CODE (SET_DEST (PATTERN (n))) == REG
5804 && GET_CODE (XEXP (SET_SRC (PATTERN (n)), 0)) == REG
5805 && REGNO (SET_DEST (PATTERN (n))) == REGNO (XEXP (SET_SRC (PATTERN (n)), 0))
5806 && GET_CODE (XEXP (SET_SRC (PATTERN (n)), 1)) == CONST_INT)
5807 {
5808 int ic = INTVAL (XEXP (SET_SRC (PATTERN (i)), 1));
5809 int nc = INTVAL (XEXP (SET_SRC (PATTERN (n)), 1));
5810 if (REGNO (SET_DEST (PATTERN (i))) == REGNO (SET_DEST (PATTERN (n)))
5811 && ic + nc < 32767
5812 && ic + nc > -32768)
5813 {
5814 XEXP (SET_SRC (PATTERN (i)), 1) = GEN_INT (ic + nc);
5815 NEXT_INSN (i) = NEXT_INSN (n);
5816 if (NEXT_INSN (i))
5817 PREV_INSN (NEXT_INSN (i)) = i;
5818 }
5819 }
5820 }
5821}
5822
5823/* If this insn adjusts the stack, return the adjustment, else return
5824 zero. */
5825static int
5826add_sp_insn_p (rtx insn)
5827{
5828 rtx pat;
5829
5830 if (! single_set (insn))
5831 return 0;
5832 pat = PATTERN (insn);
5833 if (GET_CODE (SET_DEST (pat)) != REG)
5834 return 0;
5835 if (REGNO (SET_DEST (pat)) != SP_REGNO)
5836 return 0;
5837 if (GET_CODE (SET_SRC (pat)) != PLUS)
5838 return 0;
5839 if (GET_CODE (XEXP (SET_SRC (pat), 0)) != REG)
5840 return 0;
5841 if (REGNO (XEXP (SET_SRC (pat), 0)) != SP_REGNO)
5842 return 0;
5843 if (GET_CODE (XEXP (SET_SRC (pat), 1)) != CONST_INT)
5844 return 0;
5845 return INTVAL (XEXP (SET_SRC (pat), 1));
5846}
5847
5848/* Check for trivial functions that set up an unneeded stack
5849 frame. */
5850static void
5851mep_reorg_noframe (rtx insns)
5852{
5853 rtx start_frame_insn;
5854 rtx end_frame_insn = 0;
5855 int sp_adjust, sp2;
5856 rtx sp;
5857
5858 /* The first insn should be $sp = $sp + N */
5859 while (insns && ! INSN_P (insns))
5860 insns = NEXT_INSN (insns);
5861 if (!insns)
5862 return;
5863
5864 sp_adjust = add_sp_insn_p (insns);
5865 if (sp_adjust == 0)
5866 return;
5867
5868 start_frame_insn = insns;
5869 sp = SET_DEST (PATTERN (start_frame_insn));
5870
5871 insns = next_real_insn (insns);
5872
5873 while (insns)
5874 {
5875 rtx next = next_real_insn (insns);
5876 if (!next)
5877 break;
5878
5879 sp2 = add_sp_insn_p (insns);
5880 if (sp2)
5881 {
5882 if (end_frame_insn)
5883 return;
5884 end_frame_insn = insns;
5885 if (sp2 != -sp_adjust)
5886 return;
5887 }
5888 else if (mep_mentioned_p (insns, sp, 0))
5889 return;
5890 else if (CALL_P (insns))
5891 return;
5892
5893 insns = next;
5894 }
5895
5896 if (end_frame_insn)
5897 {
5898 delete_insn (start_frame_insn);
5899 delete_insn (end_frame_insn);
5900 }
5901}
5902
5903static void
5904mep_reorg (void)
5905{
5906 rtx insns = get_insns ();
e756464b
DD
5907
5908 /* We require accurate REG_DEAD notes. */
5909 compute_bb_for_insn ();
5910 df_note_add_problem ();
5911 df_analyze ();
5912
7acf4da6
DD
5913 mep_reorg_addcombine (insns);
5914#if EXPERIMENTAL_REGMOVE_REORG
5915 /* VLIW packing has been done already, so we can't just delete things. */
5916 if (!mep_vliw_function_p (cfun->decl))
5917 mep_reorg_regmove (insns);
5918#endif
5919 mep_jmp_return_reorg (insns);
5920 mep_bundle_insns (insns);
5921 mep_reorg_repeat (insns);
5922 if (optimize
5923 && !profile_flag
5924 && !profile_arc_flag
5925 && TARGET_OPT_REPEAT
5926 && (!mep_interrupt_p () || mep_interrupt_saved_reg (RPB_REGNO)))
5927 mep_reorg_erepeat (insns);
5928
5929 /* This may delete *insns so make sure it's last. */
5930 mep_reorg_noframe (insns);
e756464b
DD
5931
5932 df_finish_pass (false);
7acf4da6
DD
5933}
5934
5935\f
5936
5937/*----------------------------------------------------------------------*/
5938/* Builtins */
5939/*----------------------------------------------------------------------*/
5940
5941/* Element X gives the index into cgen_insns[] of the most general
5942 implementation of intrinsic X. Unimplemented intrinsics are
5943 mapped to -1. */
5944int mep_intrinsic_insn[ARRAY_SIZE (cgen_intrinsics)];
5945
5946/* Element X gives the index of another instruction that is mapped to
5947 the same intrinsic as cgen_insns[X]. It is -1 when there is no other
5948 instruction.
5949
5950 Things are set up so that mep_intrinsic_chain[X] < X. */
5951static int mep_intrinsic_chain[ARRAY_SIZE (cgen_insns)];
5952
5953/* The bitmask for the current ISA. The ISA masks are declared
5954 in mep-intrin.h. */
5955unsigned int mep_selected_isa;
5956
5957struct mep_config {
5958 const char *config_name;
5959 unsigned int isa;
5960};
5961
5962static struct mep_config mep_configs[] = {
5963#ifdef COPROC_SELECTION_TABLE
5964 COPROC_SELECTION_TABLE,
5965#endif
5966 { 0, 0 }
5967};
5968
5969/* Initialize the global intrinsics variables above. */
5970
5971static void
5972mep_init_intrinsics (void)
5973{
5974 size_t i;
5975
5976 /* Set MEP_SELECTED_ISA to the ISA flag for this configuration. */
5977 mep_selected_isa = mep_configs[0].isa;
5978 if (mep_config_string != 0)
5979 for (i = 0; mep_configs[i].config_name; i++)
5980 if (strcmp (mep_config_string, mep_configs[i].config_name) == 0)
5981 {
5982 mep_selected_isa = mep_configs[i].isa;
5983 break;
5984 }
5985
5986 /* Assume all intrinsics are unavailable. */
5987 for (i = 0; i < ARRAY_SIZE (mep_intrinsic_insn); i++)
5988 mep_intrinsic_insn[i] = -1;
5989
5990 /* Build up the global intrinsic tables. */
5991 for (i = 0; i < ARRAY_SIZE (cgen_insns); i++)
5992 if ((cgen_insns[i].isas & mep_selected_isa) != 0)
5993 {
5994 mep_intrinsic_chain[i] = mep_intrinsic_insn[cgen_insns[i].intrinsic];
5995 mep_intrinsic_insn[cgen_insns[i].intrinsic] = i;
5996 }
5997 /* See whether we can directly move values between one coprocessor
5998 register and another. */
5999 for (i = 0; i < ARRAY_SIZE (mep_cmov_insns); i++)
6000 if (MEP_INTRINSIC_AVAILABLE_P (mep_cmov_insns[i]))
6001 mep_have_copro_copro_moves_p = true;
6002
6003 /* See whether we can directly move values between core and
6004 coprocessor registers. */
6005 mep_have_core_copro_moves_p = (MEP_INTRINSIC_AVAILABLE_P (mep_cmov1)
6006 && MEP_INTRINSIC_AVAILABLE_P (mep_cmov2));
6007
6008 mep_have_core_copro_moves_p = 1;
6009}
6010
6011/* Declare all available intrinsic functions. Called once only. */
6012
6013static tree cp_data_bus_int_type_node;
6014static tree opaque_vector_type_node;
6015static tree v8qi_type_node;
6016static tree v4hi_type_node;
6017static tree v2si_type_node;
6018static tree v8uqi_type_node;
6019static tree v4uhi_type_node;
6020static tree v2usi_type_node;
6021
6022static tree
6023mep_cgen_regnum_to_type (enum cgen_regnum_operand_type cr)
6024{
6025 switch (cr)
6026 {
6027 case cgen_regnum_operand_type_POINTER: return ptr_type_node;
6028 case cgen_regnum_operand_type_LONG: return long_integer_type_node;
6029 case cgen_regnum_operand_type_ULONG: return long_unsigned_type_node;
6030 case cgen_regnum_operand_type_SHORT: return short_integer_type_node;
6031 case cgen_regnum_operand_type_USHORT: return short_unsigned_type_node;
6032 case cgen_regnum_operand_type_CHAR: return char_type_node;
6033 case cgen_regnum_operand_type_UCHAR: return unsigned_char_type_node;
6034 case cgen_regnum_operand_type_SI: return intSI_type_node;
6035 case cgen_regnum_operand_type_DI: return intDI_type_node;
6036 case cgen_regnum_operand_type_VECTOR: return opaque_vector_type_node;
6037 case cgen_regnum_operand_type_V8QI: return v8qi_type_node;
6038 case cgen_regnum_operand_type_V4HI: return v4hi_type_node;
6039 case cgen_regnum_operand_type_V2SI: return v2si_type_node;
6040 case cgen_regnum_operand_type_V8UQI: return v8uqi_type_node;
6041 case cgen_regnum_operand_type_V4UHI: return v4uhi_type_node;
6042 case cgen_regnum_operand_type_V2USI: return v2usi_type_node;
6043 case cgen_regnum_operand_type_CP_DATA_BUS_INT: return cp_data_bus_int_type_node;
6044 default:
6045 return void_type_node;
6046 }
6047}
6048
6049static void
6050mep_init_builtins (void)
6051{
6052 size_t i;
6053
6054 if (TARGET_64BIT_CR_REGS)
6055 cp_data_bus_int_type_node = long_long_integer_type_node;
6056 else
6057 cp_data_bus_int_type_node = long_integer_type_node;
6058
6059 opaque_vector_type_node = build_opaque_vector_type (intQI_type_node, 8);
6060 v8qi_type_node = build_vector_type (intQI_type_node, 8);
6061 v4hi_type_node = build_vector_type (intHI_type_node, 4);
6062 v2si_type_node = build_vector_type (intSI_type_node, 2);
6063 v8uqi_type_node = build_vector_type (unsigned_intQI_type_node, 8);
6064 v4uhi_type_node = build_vector_type (unsigned_intHI_type_node, 4);
6065 v2usi_type_node = build_vector_type (unsigned_intSI_type_node, 2);
6066
6067 (*lang_hooks.decls.pushdecl)
6068 (build_decl (BUILTINS_LOCATION, TYPE_DECL, get_identifier ("cp_data_bus_int"),
6069 cp_data_bus_int_type_node));
6070
6071 (*lang_hooks.decls.pushdecl)
6072 (build_decl (BUILTINS_LOCATION, TYPE_DECL, get_identifier ("cp_vector"),
6073 opaque_vector_type_node));
6074
6075 (*lang_hooks.decls.pushdecl)
6076 (build_decl (BUILTINS_LOCATION, TYPE_DECL, get_identifier ("cp_v8qi"),
6077 v8qi_type_node));
6078 (*lang_hooks.decls.pushdecl)
6079 (build_decl (BUILTINS_LOCATION, TYPE_DECL, get_identifier ("cp_v4hi"),
6080 v4hi_type_node));
6081 (*lang_hooks.decls.pushdecl)
6082 (build_decl (BUILTINS_LOCATION, TYPE_DECL, get_identifier ("cp_v2si"),
6083 v2si_type_node));
6084
6085 (*lang_hooks.decls.pushdecl)
6086 (build_decl (BUILTINS_LOCATION, TYPE_DECL, get_identifier ("cp_v8uqi"),
6087 v8uqi_type_node));
6088 (*lang_hooks.decls.pushdecl)
6089 (build_decl (BUILTINS_LOCATION, TYPE_DECL, get_identifier ("cp_v4uhi"),
6090 v4uhi_type_node));
6091 (*lang_hooks.decls.pushdecl)
6092 (build_decl (BUILTINS_LOCATION, TYPE_DECL, get_identifier ("cp_v2usi"),
6093 v2usi_type_node));
6094
6095 /* Intrinsics like mep_cadd3 are implemented with two groups of
6096 instructions, one which uses UNSPECs and one which uses a specific
6097 rtl code such as PLUS. Instructions in the latter group belong
6098 to GROUP_KNOWN_CODE.
6099
6100 In such cases, the intrinsic will have two entries in the global
6101 tables above. The unspec form is accessed using builtin functions
6102 while the specific form is accessed using the mep_* enum in
6103 mep-intrin.h.
6104
6105 The idea is that __cop arithmetic and builtin functions have
6106 different optimization requirements. If mep_cadd3() appears in
6107 the source code, the user will surely except gcc to use cadd3
6108 rather than a work-alike such as add3. However, if the user
6109 just writes "a + b", where a or b are __cop variables, it is
6110 reasonable for gcc to choose a core instruction rather than
6111 cadd3 if it believes that is more optimal. */
6112 for (i = 0; i < ARRAY_SIZE (cgen_insns); i++)
6113 if ((cgen_insns[i].groups & GROUP_KNOWN_CODE) == 0
6114 && mep_intrinsic_insn[cgen_insns[i].intrinsic] >= 0)
6115 {
6116 tree ret_type = void_type_node;
6117 tree bi_type;
6118
6119 if (i > 0 && cgen_insns[i].intrinsic == cgen_insns[i-1].intrinsic)
6120 continue;
6121
6122 if (cgen_insns[i].cret_p)
6123 ret_type = mep_cgen_regnum_to_type (cgen_insns[i].regnums[0].type);
6124
6125 bi_type = build_function_type (ret_type, 0);
6126 add_builtin_function (cgen_intrinsics[cgen_insns[i].intrinsic],
6127 bi_type,
6128 cgen_insns[i].intrinsic, BUILT_IN_MD, NULL, NULL);
6129 }
6130}
6131
6132/* Report the unavailablity of the given intrinsic. */
6133
6134#if 1
6135static void
6136mep_intrinsic_unavailable (int intrinsic)
6137{
6138 static int already_reported_p[ARRAY_SIZE (cgen_intrinsics)];
6139
6140 if (already_reported_p[intrinsic])
6141 return;
6142
6143 if (mep_intrinsic_insn[intrinsic] < 0)
6144 error ("coprocessor intrinsic %qs is not available in this configuration",
6145 cgen_intrinsics[intrinsic]);
6146 else if (CGEN_CURRENT_GROUP == GROUP_VLIW)
6147 error ("%qs is not available in VLIW functions",
6148 cgen_intrinsics[intrinsic]);
6149 else
6150 error ("%qs is not available in non-VLIW functions",
6151 cgen_intrinsics[intrinsic]);
6152
6153 already_reported_p[intrinsic] = 1;
6154}
6155#endif
6156
6157
6158/* See if any implementation of INTRINSIC is available to the
6159 current function. If so, store the most general implementation
6160 in *INSN_PTR and return true. Return false otherwise. */
6161
6162static bool
6163mep_get_intrinsic_insn (int intrinsic ATTRIBUTE_UNUSED, const struct cgen_insn **insn_ptr ATTRIBUTE_UNUSED)
6164{
6165 int i;
6166
6167 i = mep_intrinsic_insn[intrinsic];
6168 while (i >= 0 && !CGEN_ENABLE_INSN_P (i))
6169 i = mep_intrinsic_chain[i];
6170
6171 if (i >= 0)
6172 {
6173 *insn_ptr = &cgen_insns[i];
6174 return true;
6175 }
6176 return false;
6177}
6178
6179
6180/* Like mep_get_intrinsic_insn, but with extra handling for moves.
6181 If INTRINSIC is mep_cmov, but there is no pure CR <- CR move insn,
6182 try using a work-alike instead. In this case, the returned insn
6183 may have three operands rather than two. */
6184
6185static bool
6186mep_get_move_insn (int intrinsic, const struct cgen_insn **cgen_insn)
6187{
6188 size_t i;
6189
6190 if (intrinsic == mep_cmov)
6191 {
6192 for (i = 0; i < ARRAY_SIZE (mep_cmov_insns); i++)
6193 if (mep_get_intrinsic_insn (mep_cmov_insns[i], cgen_insn))
6194 return true;
6195 return false;
6196 }
6197 return mep_get_intrinsic_insn (intrinsic, cgen_insn);
6198}
6199
6200
6201/* If ARG is a register operand that is the same size as MODE, convert it
6202 to MODE using a subreg. Otherwise return ARG as-is. */
6203
6204static rtx
6205mep_convert_arg (enum machine_mode mode, rtx arg)
6206{
6207 if (GET_MODE (arg) != mode
6208 && register_operand (arg, VOIDmode)
6209 && GET_MODE_SIZE (GET_MODE (arg)) == GET_MODE_SIZE (mode))
6210 return simplify_gen_subreg (mode, arg, GET_MODE (arg), 0);
6211 return arg;
6212}
6213
6214
6215/* Apply regnum conversions to ARG using the description given by REGNUM.
6216 Return the new argument on success and null on failure. */
6217
6218static rtx
6219mep_convert_regnum (const struct cgen_regnum_operand *regnum, rtx arg)
6220{
6221 if (regnum->count == 0)
6222 return arg;
6223
6224 if (GET_CODE (arg) != CONST_INT
6225 || INTVAL (arg) < 0
6226 || INTVAL (arg) >= regnum->count)
6227 return 0;
6228
6229 return gen_rtx_REG (SImode, INTVAL (arg) + regnum->base);
6230}
6231
6232
6233/* Try to make intrinsic argument ARG match the given operand.
6234 UNSIGNED_P is true if the argument has an unsigned type. */
6235
6236static rtx
6237mep_legitimize_arg (const struct insn_operand_data *operand, rtx arg,
6238 int unsigned_p)
6239{
6240 if (GET_CODE (arg) == CONST_INT)
6241 {
6242 /* CONST_INTs can only be bound to integer operands. */
6243 if (GET_MODE_CLASS (operand->mode) != MODE_INT)
6244 return 0;
6245 }
6246 else if (GET_CODE (arg) == CONST_DOUBLE)
6247 /* These hold vector constants. */;
6248 else if (GET_MODE_SIZE (GET_MODE (arg)) != GET_MODE_SIZE (operand->mode))
6249 {
6250 /* If the argument is a different size from what's expected, we must
6251 have a value in the right mode class in order to convert it. */
6252 if (GET_MODE_CLASS (operand->mode) != GET_MODE_CLASS (GET_MODE (arg)))
6253 return 0;
6254
6255 /* If the operand is an rvalue, promote or demote it to match the
6256 operand's size. This might not need extra instructions when
6257 ARG is a register value. */
6258 if (operand->constraint[0] != '=')
6259 arg = convert_to_mode (operand->mode, arg, unsigned_p);
6260 }
6261
6262 /* If the operand is an lvalue, bind the operand to a new register.
6263 The caller will copy this value into ARG after the main
6264 instruction. By doing this always, we produce slightly more
6265 optimal code. */
6266 /* But not for control registers. */
6267 if (operand->constraint[0] == '='
6268 && (! REG_P (arg)
072ebd49
DD
6269 || ! (CONTROL_REGNO_P (REGNO (arg))
6270 || CCR_REGNO_P (REGNO (arg))
6271 || CR_REGNO_P (REGNO (arg)))
7acf4da6
DD
6272 ))
6273 return gen_reg_rtx (operand->mode);
6274
6275 /* Try simple mode punning. */
6276 arg = mep_convert_arg (operand->mode, arg);
6277 if (operand->predicate (arg, operand->mode))
6278 return arg;
6279
6280 /* See if forcing the argument into a register will make it match. */
6281 if (GET_CODE (arg) == CONST_INT || GET_CODE (arg) == CONST_DOUBLE)
6282 arg = force_reg (operand->mode, arg);
6283 else
6284 arg = mep_convert_arg (operand->mode, force_reg (GET_MODE (arg), arg));
6285 if (operand->predicate (arg, operand->mode))
6286 return arg;
6287
6288 return 0;
6289}
6290
6291
6292/* Report that ARG cannot be passed to argument ARGNUM of intrinsic
6293 function FNNAME. OPERAND describes the operand to which ARGNUM
6294 is mapped. */
6295
6296static void
6297mep_incompatible_arg (const struct insn_operand_data *operand, rtx arg,
6298 int argnum, tree fnname)
6299{
6300 size_t i;
6301
6302 if (GET_CODE (arg) == CONST_INT)
6303 for (i = 0; i < ARRAY_SIZE (cgen_immediate_predicates); i++)
6304 if (operand->predicate == cgen_immediate_predicates[i].predicate)
6305 {
6306 const struct cgen_immediate_predicate *predicate;
6307 HOST_WIDE_INT argval;
6308
6309 predicate = &cgen_immediate_predicates[i];
6310 argval = INTVAL (arg);
6311 if (argval < predicate->lower || argval >= predicate->upper)
6312 error ("argument %d of %qE must be in the range %d...%d",
6313 argnum, fnname, predicate->lower, predicate->upper - 1);
6314 else
6315 error ("argument %d of %qE must be a multiple of %d",
6316 argnum, fnname, predicate->align);
6317 return;
6318 }
6319
6320 error ("incompatible type for argument %d of %qE", argnum, fnname);
6321}
6322
6323static rtx
6324mep_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6325 rtx subtarget ATTRIBUTE_UNUSED,
6326 enum machine_mode mode ATTRIBUTE_UNUSED,
6327 int ignore ATTRIBUTE_UNUSED)
6328{
6329 rtx pat, op[10], arg[10];
6330 unsigned int a;
6331 int opindex, unsigned_p[10];
6332 tree fndecl, args;
6333 unsigned int n_args;
6334 tree fnname;
6335 const struct cgen_insn *cgen_insn;
6336 const struct insn_data *idata;
6337 int first_arg = 0;
6338 int return_type = void_type_node;
6339 int builtin_n_args;
6340
6341 fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
6342 fnname = DECL_NAME (fndecl);
6343
6344 /* Find out which instruction we should emit. Note that some coprocessor
6345 intrinsics may only be available in VLIW mode, or only in normal mode. */
6346 if (!mep_get_intrinsic_insn (DECL_FUNCTION_CODE (fndecl), &cgen_insn))
6347 {
6348 mep_intrinsic_unavailable (DECL_FUNCTION_CODE (fndecl));
6349 return error_mark_node;
6350 }
6351 idata = &insn_data[cgen_insn->icode];
6352
6353 builtin_n_args = cgen_insn->num_args;
6354
6355 if (cgen_insn->cret_p)
6356 {
6357 if (cgen_insn->cret_p > 1)
6358 builtin_n_args ++;
6359 first_arg = 1;
6360 return_type = mep_cgen_regnum_to_type (cgen_insn->regnums[0].type);
6361 builtin_n_args --;
6362 }
6363
6364 /* Evaluate each argument. */
6365 n_args = call_expr_nargs (exp);
6366
6367 if (n_args < builtin_n_args)
6368 {
6369 error ("too few arguments to %qE", fnname);
6370 return error_mark_node;
6371 }
6372 if (n_args > builtin_n_args)
6373 {
6374 error ("too many arguments to %qE", fnname);
6375 return error_mark_node;
6376 }
6377
6378 for (a = first_arg; a < builtin_n_args+first_arg; a++)
6379 {
6380 tree value;
6381
6382 args = CALL_EXPR_ARG (exp, a-first_arg);
6383
6384 value = args;
6385
6386#if 0
6387 if (cgen_insn->regnums[a].reference_p)
6388 {
6389 if (TREE_CODE (value) != ADDR_EXPR)
6390 {
6391 debug_tree(value);
6392 error ("argument %d of %qE must be an address", a+1, fnname);
6393 return error_mark_node;
6394 }
6395 value = TREE_OPERAND (value, 0);
6396 }
6397#endif
6398
6399 /* If the argument has been promoted to int, get the unpromoted
6400 value. This is necessary when sub-int memory values are bound
6401 to reference parameters. */
6402 if (TREE_CODE (value) == NOP_EXPR
6403 && TREE_TYPE (value) == integer_type_node
6404 && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
6405 && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))
6406 < TYPE_PRECISION (TREE_TYPE (value))))
6407 value = TREE_OPERAND (value, 0);
6408
6409 /* If the argument has been promoted to double, get the unpromoted
6410 SFmode value. This is necessary for FMAX support, for example. */
6411 if (TREE_CODE (value) == NOP_EXPR
6412 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (value))
6413 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
6414 && TYPE_MODE (TREE_TYPE (value)) == DFmode
6415 && TYPE_MODE (TREE_TYPE (TREE_OPERAND (value, 0))) == SFmode)
6416 value = TREE_OPERAND (value, 0);
6417
6418 unsigned_p[a] = TYPE_UNSIGNED (TREE_TYPE (value));
6419 arg[a] = expand_expr (value, NULL, VOIDmode, EXPAND_NORMAL);
6420 arg[a] = mep_convert_regnum (&cgen_insn->regnums[a], arg[a]);
6421 if (cgen_insn->regnums[a].reference_p)
6422 {
6423 tree pointed_to = TREE_TYPE (TREE_TYPE (value));
6424 enum machine_mode pointed_mode = TYPE_MODE (pointed_to);
6425
6426 arg[a] = gen_rtx_MEM (pointed_mode, arg[a]);
6427 }
6428 if (arg[a] == 0)
6429 {
6430 error ("argument %d of %qE must be in the range %d...%d",
6431 a + 1, fnname, 0, cgen_insn->regnums[a].count - 1);
6432 return error_mark_node;
6433 }
6434 }
6435
6436 for (a=0; a<first_arg; a++)
6437 {
6438 if (a == 0 && target && GET_MODE (target) == idata->operand[0].mode)
6439 arg[a] = target;
6440 else
6441 arg[a] = gen_reg_rtx (idata->operand[0].mode);
6442 }
6443
6444 /* Convert the arguments into a form suitable for the intrinsic.
6445 Report an error if this isn't possible. */
6446 for (opindex = 0; opindex < idata->n_operands; opindex++)
6447 {
6448 a = cgen_insn->op_mapping[opindex];
6449 op[opindex] = mep_legitimize_arg (&idata->operand[opindex],
6450 arg[a], unsigned_p[a]);
6451 if (op[opindex] == 0)
6452 {
6453 mep_incompatible_arg (&idata->operand[opindex],
6454 arg[a], a + 1 - first_arg, fnname);
6455 return error_mark_node;
6456 }
6457 }
6458
6459 /* Emit the instruction. */
6460 pat = idata->genfun (op[0], op[1], op[2], op[3], op[4],
6461 op[5], op[6], op[7], op[8], op[9]);
6462
6463 if (GET_CODE (pat) == SET
6464 && GET_CODE (SET_DEST (pat)) == PC
6465 && GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE)
6466 emit_jump_insn (pat);
6467 else
6468 emit_insn (pat);
6469
6470 /* Copy lvalues back to their final locations. */
6471 for (opindex = 0; opindex < idata->n_operands; opindex++)
6472 if (idata->operand[opindex].constraint[0] == '=')
6473 {
6474 a = cgen_insn->op_mapping[opindex];
6475 if (a >= first_arg)
6476 {
6477 if (GET_MODE_CLASS (GET_MODE (arg[a]))
6478 != GET_MODE_CLASS (GET_MODE (op[opindex])))
6479 emit_move_insn (arg[a], gen_lowpart (GET_MODE (arg[a]),
6480 op[opindex]));
6481 else
6482 {
6483 /* First convert the operand to the right mode, then copy it
6484 into the destination. Doing the conversion as a separate
6485 step (rather than using convert_move) means that we can
6486 avoid creating no-op moves when ARG[A] and OP[OPINDEX]
6487 refer to the same register. */
6488 op[opindex] = convert_to_mode (GET_MODE (arg[a]),
6489 op[opindex], unsigned_p[a]);
6490 if (!rtx_equal_p (arg[a], op[opindex]))
6491 emit_move_insn (arg[a], op[opindex]);
6492 }
6493 }
6494 }
6495
6496 if (first_arg > 0 && target && target != op[0])
6497 {
6498 emit_move_insn (target, op[0]);
6499 }
6500
6501 return target;
6502}
6503
6504static bool
6505mep_vector_mode_supported_p (enum machine_mode mode ATTRIBUTE_UNUSED)
6506{
6507 return false;
6508}
6509\f
6510/* A subroutine of global_reg_mentioned_p, returns 1 if *LOC mentions
6511 a global register. */
6512
6513static int
6514global_reg_mentioned_p_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
6515{
6516 int regno;
6517 rtx x = *loc;
6518
6519 if (! x)
6520 return 0;
6521
6522 switch (GET_CODE (x))
6523 {
6524 case SUBREG:
6525 if (REG_P (SUBREG_REG (x)))
6526 {
6527 if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER
6528 && global_regs[subreg_regno (x)])
6529 return 1;
6530 return 0;
6531 }
6532 break;
6533
6534 case REG:
6535 regno = REGNO (x);
6536 if (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
6537 return 1;
6538 return 0;
6539
6540 case SCRATCH:
6541 case PC:
6542 case CC0:
6543 case CONST_INT:
6544 case CONST_DOUBLE:
6545 case CONST:
6546 case LABEL_REF:
6547 return 0;
6548
6549 case CALL:
6550 /* A non-constant call might use a global register. */
6551 return 1;
6552
6553 default:
6554 break;
6555 }
6556
6557 return 0;
6558}
6559
6560/* Returns nonzero if X mentions a global register. */
6561
6562static int
6563global_reg_mentioned_p (rtx x)
6564{
6565 if (INSN_P (x))
6566 {
6567 if (CALL_P (x))
6568 {
6569 if (! RTL_CONST_OR_PURE_CALL_P (x))
6570 return 1;
6571 x = CALL_INSN_FUNCTION_USAGE (x);
6572 if (x == 0)
6573 return 0;
6574 }
6575 else
6576 x = PATTERN (x);
6577 }
6578
6579 return for_each_rtx (&x, global_reg_mentioned_p_1, NULL);
6580}
6581/* Scheduling hooks for VLIW mode.
6582
6583 Conceptually this is very simple: we have a two-pack architecture
6584 that takes one core insn and one coprocessor insn to make up either
6585 a 32- or 64-bit instruction word (depending on the option bit set in
6586 the chip). I.e. in VL32 mode, we can pack one 16-bit core insn and
6587 one 16-bit cop insn; in VL64 mode we can pack one 16-bit core insn
6588 and one 48-bit cop insn or two 32-bit core/cop insns.
6589
6590 In practice, instruction selection will be a bear. Consider in
6591 VL64 mode the following insns
6592
6593 add $1, 1
6594 cmov $cr0, $0
6595
6596 these cannot pack, since the add is a 16-bit core insn and cmov
6597 is a 32-bit cop insn. However,
6598
6599 add3 $1, $1, 1
6600 cmov $cr0, $0
6601
6602 packs just fine. For good VLIW code generation in VL64 mode, we
6603 will have to have 32-bit alternatives for many of the common core
6604 insns. Not implemented. */
6605
6606static int
6607mep_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
6608{
6609 int cost_specified;
6610
6611 if (REG_NOTE_KIND (link) != 0)
6612 {
6613 /* See whether INSN and DEP_INSN are intrinsics that set the same
6614 hard register. If so, it is more important to free up DEP_INSN
6615 than it is to free up INSN.
6616
6617 Note that intrinsics like mep_mulr are handled differently from
6618 the equivalent mep.md patterns. In mep.md, if we don't care
6619 about the value of $lo and $hi, the pattern will just clobber
6620 the registers, not set them. Since clobbers don't count as
6621 output dependencies, it is often possible to reorder two mulrs,
6622 even after reload.
6623
6624 In contrast, mep_mulr() sets both $lo and $hi to specific values,
6625 so any pair of mep_mulr()s will be inter-dependent. We should
6626 therefore give the first mep_mulr() a higher priority. */
6627 if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT
6628 && global_reg_mentioned_p (PATTERN (insn))
6629 && global_reg_mentioned_p (PATTERN (dep_insn)))
6630 return 1;
6631
6632 /* If the dependence is an anti or output dependence, assume it
6633 has no cost. */
6634 return 0;
6635 }
6636
6637 /* If we can't recognize the insns, we can't really do anything. */
6638 if (recog_memoized (dep_insn) < 0)
6639 return cost;
6640
6641 /* The latency attribute doesn't apply to MeP-h1: we use the stall
6642 attribute instead. */
6643 if (!TARGET_H1)
6644 {
6645 cost_specified = get_attr_latency (dep_insn);
6646 if (cost_specified != 0)
6647 return cost_specified;
6648 }
6649
6650 return cost;
6651}
6652
6653/* ??? We don't properly compute the length of a load/store insn,
6654 taking into account the addressing mode. */
6655
6656static int
6657mep_issue_rate (void)
6658{
6659 return TARGET_IVC2 ? 3 : 2;
6660}
6661
6662/* Return true if function DECL was declared with the vliw attribute. */
6663
6664bool
6665mep_vliw_function_p (tree decl)
6666{
6667 return lookup_attribute ("vliw", TYPE_ATTRIBUTES (TREE_TYPE (decl))) != 0;
6668}
6669
6670static rtx
6671mep_find_ready_insn (rtx *ready, int nready, enum attr_slot slot, int length)
6672{
6673 int i;
6674
6675 for (i = nready - 1; i >= 0; --i)
6676 {
6677 rtx insn = ready[i];
6678 if (recog_memoized (insn) >= 0
6679 && get_attr_slot (insn) == slot
6680 && get_attr_length (insn) == length)
6681 return insn;
6682 }
6683
6684 return NULL_RTX;
6685}
6686
6687static void
6688mep_move_ready_insn (rtx *ready, int nready, rtx insn)
6689{
6690 int i;
6691
6692 for (i = 0; i < nready; ++i)
6693 if (ready[i] == insn)
6694 {
6695 for (; i < nready - 1; ++i)
6696 ready[i] = ready[i + 1];
6697 ready[i] = insn;
6698 return;
6699 }
6700
6701 gcc_unreachable ();
6702}
6703
6704static void
6705mep_print_sched_insn (FILE *dump, rtx insn)
6706{
6707 const char *slots = "none";
6708 const char *name = NULL;
6709 int code;
6710 char buf[30];
6711
6712 if (GET_CODE (PATTERN (insn)) == SET
6713 || GET_CODE (PATTERN (insn)) == PARALLEL)
6714 {
6715 switch (get_attr_slots (insn))
6716 {
6717 case SLOTS_CORE: slots = "core"; break;
6718 case SLOTS_C3: slots = "c3"; break;
6719 case SLOTS_P0: slots = "p0"; break;
6720 case SLOTS_P0_P0S: slots = "p0,p0s"; break;
6721 case SLOTS_P0_P1: slots = "p0,p1"; break;
6722 case SLOTS_P0S: slots = "p0s"; break;
6723 case SLOTS_P0S_P1: slots = "p0s,p1"; break;
6724 case SLOTS_P1: slots = "p1"; break;
6725 default:
6726 sprintf(buf, "%d", get_attr_slots (insn));
6727 slots = buf;
6728 break;
6729 }
6730 }
6731 if (GET_CODE (PATTERN (insn)) == USE)
6732 slots = "use";
6733
6734 code = INSN_CODE (insn);
6735 if (code >= 0)
6736 name = get_insn_name (code);
6737 if (!name)
6738 name = "{unknown}";
6739
6740 fprintf (dump,
6741 "insn %4d %4d %8s %s\n",
6742 code,
6743 INSN_UID (insn),
6744 name,
6745 slots);
6746}
6747
6748static int
6749mep_sched_reorder (FILE *dump ATTRIBUTE_UNUSED,
6750 int sched_verbose ATTRIBUTE_UNUSED, rtx *ready,
6751 int *pnready, int clock ATTRIBUTE_UNUSED)
6752{
6753 int nready = *pnready;
6754 rtx core_insn, cop_insn;
6755 int i;
6756
6757 if (dump && sched_verbose > 1)
6758 {
6759 fprintf (dump, "\nsched_reorder: clock %d nready %d\n", clock, nready);
6760 for (i=0; i<nready; i++)
6761 mep_print_sched_insn (dump, ready[i]);
6762 fprintf (dump, "\n");
6763 }
6764
6765 if (!mep_vliw_function_p (cfun->decl))
6766 return 1;
6767 if (nready < 2)
6768 return 1;
6769
6770 /* IVC2 uses a DFA to determine what's ready and what's not. */
6771 if (TARGET_IVC2)
6772 return nready;
6773
6774 /* We can issue either a core or coprocessor instruction.
6775 Look for a matched pair of insns to reorder. If we don't
6776 find any, don't second-guess the scheduler's priorities. */
6777
6778 if ((core_insn = mep_find_ready_insn (ready, nready, SLOT_CORE, 2))
6779 && (cop_insn = mep_find_ready_insn (ready, nready, SLOT_COP,
6780 TARGET_OPT_VL64 ? 6 : 2)))
6781 ;
6782 else if (TARGET_OPT_VL64
6783 && (core_insn = mep_find_ready_insn (ready, nready, SLOT_CORE, 4))
6784 && (cop_insn = mep_find_ready_insn (ready, nready, SLOT_COP, 4)))
6785 ;
6786 else
6787 /* We didn't find a pair. Issue the single insn at the head
6788 of the ready list. */
6789 return 1;
6790
6791 /* Reorder the two insns first. */
6792 mep_move_ready_insn (ready, nready, core_insn);
6793 mep_move_ready_insn (ready, nready - 1, cop_insn);
6794 return 2;
6795}
6796
6797/* A for_each_rtx callback. Return true if *X is a register that is
6798 set by insn PREV. */
6799
6800static int
6801mep_store_find_set (rtx *x, void *prev)
6802{
6803 return REG_P (*x) && reg_set_p (*x, (const_rtx) prev);
6804}
6805
6806/* Like mep_store_bypass_p, but takes a pattern as the second argument,
6807 not the containing insn. */
6808
6809static bool
6810mep_store_data_bypass_1 (rtx prev, rtx pat)
6811{
6812 /* Cope with intrinsics like swcpa. */
6813 if (GET_CODE (pat) == PARALLEL)
6814 {
6815 int i;
6816
6817 for (i = 0; i < XVECLEN (pat, 0); i++)
6818 if (mep_store_data_bypass_p (prev, XVECEXP (pat, 0, i)))
6819 return true;
6820
6821 return false;
6822 }
6823
6824 /* Check for some sort of store. */
6825 if (GET_CODE (pat) != SET
6826 || GET_CODE (SET_DEST (pat)) != MEM)
6827 return false;
6828
6829 /* Intrinsics use patterns of the form (set (mem (scratch)) (unspec ...)).
6830 The first operand to the unspec is the store data and the other operands
6831 are used to calculate the address. */
6832 if (GET_CODE (SET_SRC (pat)) == UNSPEC)
6833 {
6834 rtx src;
6835 int i;
6836
6837 src = SET_SRC (pat);
6838 for (i = 1; i < XVECLEN (src, 0); i++)
6839 if (for_each_rtx (&XVECEXP (src, 0, i), mep_store_find_set, prev))
6840 return false;
6841
6842 return true;
6843 }
6844
6845 /* Otherwise just check that PREV doesn't modify any register mentioned
6846 in the memory destination. */
6847 return !for_each_rtx (&SET_DEST (pat), mep_store_find_set, prev);
6848}
6849
6850/* Return true if INSN is a store instruction and if the store address
6851 has no true dependence on PREV. */
6852
6853bool
6854mep_store_data_bypass_p (rtx prev, rtx insn)
6855{
6856 return INSN_P (insn) ? mep_store_data_bypass_1 (prev, PATTERN (insn)) : false;
6857}
6858
6859/* A for_each_rtx subroutine of mep_mul_hilo_bypass_p. Return 1 if *X
6860 is a register other than LO or HI and if PREV sets *X. */
6861
6862static int
6863mep_mul_hilo_bypass_1 (rtx *x, void *prev)
6864{
6865 return (REG_P (*x)
6866 && REGNO (*x) != LO_REGNO
6867 && REGNO (*x) != HI_REGNO
6868 && reg_set_p (*x, (const_rtx) prev));
6869}
6870
6871/* Return true if, apart from HI/LO, there are no true dependencies
6872 between multiplication instructions PREV and INSN. */
6873
6874bool
6875mep_mul_hilo_bypass_p (rtx prev, rtx insn)
6876{
6877 rtx pat;
6878
6879 pat = PATTERN (insn);
6880 if (GET_CODE (pat) == PARALLEL)
6881 pat = XVECEXP (pat, 0, 0);
6882 return (GET_CODE (pat) == SET
6883 && !for_each_rtx (&SET_SRC (pat), mep_mul_hilo_bypass_1, prev));
6884}
6885
6886/* Return true if INSN is an ldc instruction that issues to the
6887 MeP-h1 integer pipeline. This is true for instructions that
6888 read from PSW, LP, SAR, HI and LO. */
6889
6890bool
6891mep_ipipe_ldc_p (rtx insn)
6892{
6893 rtx pat, src;
6894
6895 pat = PATTERN (insn);
6896
6897 /* Cope with instrinsics that set both a hard register and its shadow.
6898 The set of the hard register comes first. */
6899 if (GET_CODE (pat) == PARALLEL)
6900 pat = XVECEXP (pat, 0, 0);
6901
6902 if (GET_CODE (pat) == SET)
6903 {
6904 src = SET_SRC (pat);
6905
6906 /* Cope with intrinsics. The first operand to the unspec is
6907 the source register. */
6908 if (GET_CODE (src) == UNSPEC || GET_CODE (src) == UNSPEC_VOLATILE)
6909 src = XVECEXP (src, 0, 0);
6910
6911 if (REG_P (src))
6912 switch (REGNO (src))
6913 {
6914 case PSW_REGNO:
6915 case LP_REGNO:
6916 case SAR_REGNO:
6917 case HI_REGNO:
6918 case LO_REGNO:
6919 return true;
6920 }
6921 }
6922 return false;
6923}
6924
6925/* Create a VLIW bundle from core instruction CORE and coprocessor
6926 instruction COP. COP always satisfies INSN_P, but CORE can be
6927 either a new pattern or an existing instruction.
6928
6929 Emit the bundle in place of COP and return it. */
6930
6931static rtx
6932mep_make_bundle (rtx core, rtx cop)
6933{
6934 rtx insn;
6935
6936 /* If CORE is an existing instruction, remove it, otherwise put
6937 the new pattern in an INSN harness. */
6938 if (INSN_P (core))
6939 remove_insn (core);
6940 else
6941 core = make_insn_raw (core);
6942
6943 /* Generate the bundle sequence and replace COP with it. */
6944 insn = gen_rtx_SEQUENCE (VOIDmode, gen_rtvec (2, core, cop));
6945 insn = emit_insn_after (insn, cop);
6946 remove_insn (cop);
6947
6948 /* Set up the links of the insns inside the SEQUENCE. */
6949 PREV_INSN (core) = PREV_INSN (insn);
6950 NEXT_INSN (core) = cop;
6951 PREV_INSN (cop) = core;
6952 NEXT_INSN (cop) = NEXT_INSN (insn);
6953
6954 /* Set the VLIW flag for the coprocessor instruction. */
6955 PUT_MODE (core, VOIDmode);
6956 PUT_MODE (cop, BImode);
6957
6958 /* Derive a location for the bundle. Individual instructions cannot
6959 have their own location because there can be no assembler labels
6960 between CORE and COP. */
6961 INSN_LOCATOR (insn) = INSN_LOCATOR (INSN_LOCATOR (core) ? core : cop);
6962 INSN_LOCATOR (core) = 0;
6963 INSN_LOCATOR (cop) = 0;
6964
6965 return insn;
6966}
6967
6968/* A helper routine for ms1_insn_dependent_p called through note_stores. */
6969
6970static void
6971mep_insn_dependent_p_1 (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
6972{
6973 rtx * pinsn = (rtx *) data;
6974
6975 if (*pinsn && reg_mentioned_p (x, *pinsn))
6976 *pinsn = NULL_RTX;
6977}
6978
6979/* Return true if anything in insn X is (anti,output,true) dependent on
6980 anything in insn Y. */
6981
6982static int
6983mep_insn_dependent_p (rtx x, rtx y)
6984{
6985 rtx tmp;
6986
6987 gcc_assert (INSN_P (x));
6988 gcc_assert (INSN_P (y));
6989
6990 tmp = PATTERN (y);
6991 note_stores (PATTERN (x), mep_insn_dependent_p_1, &tmp);
6992 if (tmp == NULL_RTX)
6993 return 1;
6994
6995 tmp = PATTERN (x);
6996 note_stores (PATTERN (y), mep_insn_dependent_p_1, &tmp);
6997 if (tmp == NULL_RTX)
6998 return 1;
6999
7000 return 0;
7001}
7002
7003static int
7004core_insn_p (rtx insn)
7005{
7006 if (GET_CODE (PATTERN (insn)) == USE)
7007 return 0;
7008 if (get_attr_slot (insn) == SLOT_CORE)
7009 return 1;
7010 return 0;
7011}
7012
7013/* Mark coprocessor instructions that can be bundled together with
7014 the immediately preceeding core instruction. This is later used
7015 to emit the "+" that tells the assembler to create a VLIW insn.
7016
7017 For unbundled insns, the assembler will automatically add coprocessor
7018 nops, and 16-bit core nops. Due to an apparent oversight in the
7019 spec, the assembler will _not_ automatically add 32-bit core nops,
7020 so we have to emit those here.
7021
7022 Called from mep_insn_reorg. */
7023
7024static void
7025mep_bundle_insns (rtx insns)
7026{
7027 rtx insn, last = NULL_RTX, first = NULL_RTX;
7028 int saw_scheduling = 0;
7029
7030 /* Only do bundling if we're in vliw mode. */
7031 if (!mep_vliw_function_p (cfun->decl))
7032 return;
7033
7034 /* The first insn in a bundle are TImode, the remainder are
7035 VOIDmode. After this function, the first has VOIDmode and the
7036 rest have BImode. */
7037
bb7681bf
DD
7038 /* Note: this doesn't appear to be true for JUMP_INSNs. */
7039
7acf4da6
DD
7040 /* First, move any NOTEs that are within a bundle, to the beginning
7041 of the bundle. */
7042 for (insn = insns; insn ; insn = NEXT_INSN (insn))
7043 {
7044 if (NOTE_P (insn) && first)
7045 /* Don't clear FIRST. */;
7046
bb7681bf 7047 else if (NONJUMP_INSN_P (insn) && GET_MODE (insn) == TImode)
7acf4da6
DD
7048 first = insn;
7049
bb7681bf 7050 else if (NONJUMP_INSN_P (insn) && GET_MODE (insn) == VOIDmode && first)
7acf4da6
DD
7051 {
7052 rtx note, prev;
7053
7054 /* INSN is part of a bundle; FIRST is the first insn in that
7055 bundle. Move all intervening notes out of the bundle.
7056 In addition, since the debug pass may insert a label
7057 whenever the current line changes, set the location info
7058 for INSN to match FIRST. */
7059
7060 INSN_LOCATOR (insn) = INSN_LOCATOR (first);
7061
7062 note = PREV_INSN (insn);
7063 while (note && note != first)
7064 {
7065 prev = PREV_INSN (note);
7066
7067 if (NOTE_P (note))
7068 {
7069 /* Remove NOTE from here... */
7070 PREV_INSN (NEXT_INSN (note)) = PREV_INSN (note);
7071 NEXT_INSN (PREV_INSN (note)) = NEXT_INSN (note);
7072 /* ...and put it in here. */
7073 NEXT_INSN (note) = first;
7074 PREV_INSN (note) = PREV_INSN (first);
7075 NEXT_INSN (PREV_INSN (note)) = note;
7076 PREV_INSN (NEXT_INSN (note)) = note;
7077 }
7078
7079 note = prev;
7080 }
7081 }
7082
bb7681bf 7083 else if (!NONJUMP_INSN_P (insn))
7acf4da6
DD
7084 first = 0;
7085 }
7086
7087 /* Now fix up the bundles. */
7088 for (insn = insns; insn ; insn = NEXT_INSN (insn))
7089 {
7090 if (NOTE_P (insn))
7091 continue;
7092
bb7681bf 7093 if (!NONJUMP_INSN_P (insn))
7acf4da6
DD
7094 {
7095 last = 0;
7096 continue;
7097 }
7098
7099 /* If we're not optimizing enough, there won't be scheduling
7100 info. We detect that here. */
7101 if (GET_MODE (insn) == TImode)
7102 saw_scheduling = 1;
7103 if (!saw_scheduling)
7104 continue;
7105
7106 if (TARGET_IVC2)
7107 {
7108 rtx core_insn = NULL_RTX;
7109
7110 /* IVC2 slots are scheduled by DFA, so we just accept
7111 whatever the scheduler gives us. However, we must make
7112 sure the core insn (if any) is the first in the bundle.
7113 The IVC2 assembler can insert whatever NOPs are needed,
7114 and allows a COP insn to be first. */
7115
bb7681bf 7116 if (NONJUMP_INSN_P (insn)
7acf4da6
DD
7117 && GET_CODE (PATTERN (insn)) != USE
7118 && GET_MODE (insn) == TImode)
7119 {
7120 for (last = insn;
7121 NEXT_INSN (last)
7122 && GET_MODE (NEXT_INSN (last)) == VOIDmode
bb7681bf 7123 && NONJUMP_INSN_P (NEXT_INSN (last));
7acf4da6
DD
7124 last = NEXT_INSN (last))
7125 {
7126 if (core_insn_p (last))
7127 core_insn = last;
7128 }
7129 if (core_insn_p (last))
7130 core_insn = last;
7131
7132 if (core_insn && core_insn != insn)
7133 {
7134 /* Swap core insn to first in the bundle. */
7135
7136 /* Remove core insn. */
7137 if (PREV_INSN (core_insn))
7138 NEXT_INSN (PREV_INSN (core_insn)) = NEXT_INSN (core_insn);
7139 if (NEXT_INSN (core_insn))
7140 PREV_INSN (NEXT_INSN (core_insn)) = PREV_INSN (core_insn);
7141
7142 /* Re-insert core insn. */
7143 PREV_INSN (core_insn) = PREV_INSN (insn);
7144 NEXT_INSN (core_insn) = insn;
7145
7146 if (PREV_INSN (core_insn))
7147 NEXT_INSN (PREV_INSN (core_insn)) = core_insn;
7148 PREV_INSN (insn) = core_insn;
7149
7150 PUT_MODE (core_insn, TImode);
7151 PUT_MODE (insn, VOIDmode);
7152 }
7153 }
7154
7155 /* The first insn has TImode, the rest have VOIDmode */
7156 if (GET_MODE (insn) == TImode)
7157 PUT_MODE (insn, VOIDmode);
7158 else
7159 PUT_MODE (insn, BImode);
7160 continue;
7161 }
7162
7163 PUT_MODE (insn, VOIDmode);
7164 if (recog_memoized (insn) >= 0
7165 && get_attr_slot (insn) == SLOT_COP)
7166 {
7167 if (GET_CODE (insn) == JUMP_INSN
7168 || ! last
7169 || recog_memoized (last) < 0
7170 || get_attr_slot (last) != SLOT_CORE
7171 || (get_attr_length (insn)
7172 != (TARGET_OPT_VL64 ? 8 : 4) - get_attr_length (last))
7173 || mep_insn_dependent_p (insn, last))
7174 {
7175 switch (get_attr_length (insn))
7176 {
7177 case 8:
7178 break;
7179 case 6:
7180 insn = mep_make_bundle (gen_nop (), insn);
7181 break;
7182 case 4:
7183 if (TARGET_OPT_VL64)
7184 insn = mep_make_bundle (gen_nop32 (), insn);
7185 break;
7186 case 2:
7187 if (TARGET_OPT_VL64)
7188 error ("2 byte cop instructions are"
7189 " not allowed in 64-bit VLIW mode");
7190 else
7191 insn = mep_make_bundle (gen_nop (), insn);
7192 break;
7193 default:
7194 error ("unexpected %d byte cop instruction",
7195 get_attr_length (insn));
7196 break;
7197 }
7198 }
7199 else
7200 insn = mep_make_bundle (last, insn);
7201 }
7202
7203 last = insn;
7204 }
7205}
7206
7207
7208/* Try to instantiate INTRINSIC with the operands given in OPERANDS.
7209 Return true on success. This function can fail if the intrinsic
7210 is unavailable or if the operands don't satisfy their predicates. */
7211
7212bool
7213mep_emit_intrinsic (int intrinsic, const rtx *operands)
7214{
7215 const struct cgen_insn *cgen_insn;
7216 const struct insn_data *idata;
7217 rtx newop[10];
7218 int i;
7219
7220 if (!mep_get_intrinsic_insn (intrinsic, &cgen_insn))
7221 return false;
7222
7223 idata = &insn_data[cgen_insn->icode];
7224 for (i = 0; i < idata->n_operands; i++)
7225 {
7226 newop[i] = mep_convert_arg (idata->operand[i].mode, operands[i]);
7227 if (!idata->operand[i].predicate (newop[i], idata->operand[i].mode))
7228 return false;
7229 }
7230
7231 emit_insn (idata->genfun (newop[0], newop[1], newop[2],
7232 newop[3], newop[4], newop[5],
7233 newop[6], newop[7], newop[8]));
7234
7235 return true;
7236}
7237
7238
7239/* Apply the given unary intrinsic to OPERANDS[1] and store it on
7240 OPERANDS[0]. Report an error if the instruction could not
7241 be synthesized. OPERANDS[1] is a register_operand. For sign
7242 and zero extensions, it may be smaller than SImode. */
7243
7244bool
7245mep_expand_unary_intrinsic (int ATTRIBUTE_UNUSED intrinsic,
7246 rtx * operands ATTRIBUTE_UNUSED)
7247{
7248 return false;
7249}
7250
7251
7252/* Likewise, but apply a binary operation to OPERANDS[1] and
7253 OPERANDS[2]. OPERANDS[1] is a register_operand, OPERANDS[2]
7254 can be a general_operand.
7255
7256 IMMEDIATE and IMMEDIATE3 are intrinsics that take an immediate
7257 third operand. REG and REG3 take register operands only. */
7258
7259bool
7260mep_expand_binary_intrinsic (int ATTRIBUTE_UNUSED immediate,
7261 int ATTRIBUTE_UNUSED immediate3,
7262 int ATTRIBUTE_UNUSED reg,
7263 int ATTRIBUTE_UNUSED reg3,
7264 rtx * operands ATTRIBUTE_UNUSED)
7265{
7266 return false;
7267}
7268
7269static bool
7270mep_rtx_cost (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total, bool ATTRIBUTE_UNUSED speed_t)
7271{
7272 switch (code)
7273 {
7274 case CONST_INT:
7275 if (INTVAL (x) >= -128 && INTVAL (x) < 127)
7276 *total = 0;
7277 else if (INTVAL (x) >= -32768 && INTVAL (x) < 65536)
7278 *total = 1;
7279 else
7280 *total = 3;
7281 return true;
7282
7283 case SYMBOL_REF:
7284 *total = optimize_size ? COSTS_N_INSNS (0) : COSTS_N_INSNS (1);
7285 return true;
7286
7287 case MULT:
7288 *total = (GET_CODE (XEXP (x, 1)) == CONST_INT
7289 ? COSTS_N_INSNS (3)
7290 : COSTS_N_INSNS (2));
7291 return true;
7292 }
7293 return false;
7294}
7295
7296static int
7297mep_address_cost (rtx addr ATTRIBUTE_UNUSED, bool ATTRIBUTE_UNUSED speed_p)
7298{
7299 return 1;
7300}
7301
7302static bool
7303mep_handle_option (size_t code,
7304 const char *arg ATTRIBUTE_UNUSED,
7305 int value ATTRIBUTE_UNUSED)
7306{
7307 int i;
7308
7309 switch (code)
7310 {
7311 case OPT_mall_opts:
7312 target_flags |= MEP_ALL_OPTS;
7313 break;
7314
7315 case OPT_mno_opts:
7316 target_flags &= ~ MEP_ALL_OPTS;
7317 break;
7318
7319 case OPT_mcop64:
7320 target_flags |= MASK_COP;
7321 target_flags |= MASK_64BIT_CR_REGS;
7322 break;
7323
7324 case OPT_mtiny_:
7325 option_mtiny_specified = 1;
7326
7327 case OPT_mivc2:
7328 target_flags |= MASK_COP;
7329 target_flags |= MASK_64BIT_CR_REGS;
7330 target_flags |= MASK_VLIW;
7331 target_flags |= MASK_OPT_VL64;
7332 target_flags |= MASK_IVC2;
7333
7334 for (i=0; i<32; i++)
7335 fixed_regs[i+48] = 0;
7336 for (i=0; i<32; i++)
7337 call_used_regs[i+48] = 1;
7338 for (i=6; i<8; i++)
7339 call_used_regs[i+48] = 0;
7340
7acf4da6
DD
7341#define RN(n,s) reg_names[FIRST_CCR_REGNO + n] = s
7342 RN (0, "$csar0");
7343 RN (1, "$cc");
7344 RN (4, "$cofr0");
7345 RN (5, "$cofr1");
7346 RN (6, "$cofa0");
7347 RN (7, "$cofa1");
7348 RN (15, "$csar1");
7349
7350 RN (16, "$acc0_0");
7351 RN (17, "$acc0_1");
7352 RN (18, "$acc0_2");
7353 RN (19, "$acc0_3");
7354 RN (20, "$acc0_4");
7355 RN (21, "$acc0_5");
7356 RN (22, "$acc0_6");
7357 RN (23, "$acc0_7");
7358
7359 RN (24, "$acc1_0");
7360 RN (25, "$acc1_1");
7361 RN (26, "$acc1_2");
7362 RN (27, "$acc1_3");
7363 RN (28, "$acc1_4");
7364 RN (29, "$acc1_5");
7365 RN (30, "$acc1_6");
7366 RN (31, "$acc1_7");
7367#undef RN
7368
7369 break;
7370
7371 default:
7372 break;
7373 }
7374 return TRUE;
7375}
7376
7377static void
7378mep_asm_init_sections (void)
7379{
7380 based_section
7381 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
7382 "\t.section .based,\"aw\"");
7383
7384 tinybss_section
7385 = get_unnamed_section (SECTION_WRITE | SECTION_BSS, output_section_asm_op,
7386 "\t.section .sbss,\"aw\"");
7387
7388 sdata_section
7389 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
7390 "\t.section .sdata,\"aw\",@progbits");
7391
7392 far_section
7393 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
7394 "\t.section .far,\"aw\"");
7395
7396 farbss_section
7397 = get_unnamed_section (SECTION_WRITE | SECTION_BSS, output_section_asm_op,
7398 "\t.section .farbss,\"aw\"");
7399
7400 frodata_section
7401 = get_unnamed_section (0, output_section_asm_op,
7402 "\t.section .frodata,\"a\"");
7403
7404 srodata_section
7405 = get_unnamed_section (0, output_section_asm_op,
7406 "\t.section .srodata,\"a\"");
7407
820ca276 7408 vtext_section
77806925
DD
7409 = get_unnamed_section (SECTION_CODE | SECTION_MEP_VLIW, output_section_asm_op,
7410 "\t.section .vtext,\"axv\"\n\t.vliw");
820ca276
DD
7411
7412 vftext_section
77806925 7413 = get_unnamed_section (SECTION_CODE | SECTION_MEP_VLIW, output_section_asm_op,
da24f9d9 7414 "\t.section .vftext,\"axv\"\n\t.vliw");
820ca276
DD
7415
7416 ftext_section
77806925 7417 = get_unnamed_section (SECTION_CODE, output_section_asm_op,
da24f9d9 7418 "\t.section .ftext,\"ax\"\n\t.core");
820ca276 7419
7acf4da6
DD
7420}
7421
7422#include "gt-mep.h"
This page took 0.804037 seconds and 5 git commands to generate.