]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/iq2000/iq2000.c
Makefile.in (TARGET_DEF): Add target-insns.def.
[thirdparty/gcc.git] / gcc / config / iq2000 / iq2000.c
CommitLineData
6b3d1e47 1/* Subroutines used for code generation on Vitesse IQ2000 processors
5624e564 2 Copyright (C) 2003-2015 Free Software Foundation, Inc.
6b3d1e47 3
b7849684 4This file is part of GCC.
6b3d1e47 5
b7849684 6GCC is free software; you can redistribute it and/or modify
6b3d1e47 7it under the terms of the GNU General Public License as published by
2f83c7d6 8the Free Software Foundation; either version 3, or (at your option)
6b3d1e47
SC
9any later version.
10
b7849684 11GCC is distributed in the hope that it will be useful,
6b3d1e47
SC
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
2f83c7d6
NC
17along with GCC; see the file COPYING3. If not see
18<http://www.gnu.org/licenses/>. */
6b3d1e47
SC
19
20#include "config.h"
21#include "system.h"
22#include "coretypes.h"
6b3d1e47 23#include "tm.h"
40e23961
MC
24#include "alias.h"
25#include "symtab.h"
6b3d1e47 26#include "tree.h"
40e23961 27#include "fold-const.h"
d8a2d370
DN
28#include "stor-layout.h"
29#include "calls.h"
30#include "varasm.h"
6b3d1e47
SC
31#include "rtl.h"
32#include "regs.h"
33#include "hard-reg-set.h"
6b3d1e47
SC
34#include "insn-config.h"
35#include "conditions.h"
36#include "output.h"
37#include "insn-attr.h"
38#include "flags.h"
39#include "function.h"
36566b39
PK
40#include "expmed.h"
41#include "dojump.h"
42#include "explow.h"
43#include "emit-rtl.h"
44#include "stmt.h"
6b3d1e47 45#include "expr.h"
b0710fe1 46#include "insn-codes.h"
6b3d1e47
SC
47#include "optabs.h"
48#include "libfuncs.h"
49#include "recog.h"
718f9c0f 50#include "diagnostic-core.h"
6b3d1e47 51#include "reload.h"
6b3d1e47
SC
52#include "tm_p.h"
53#include "debug.h"
54#include "target.h"
6e34d3a3 55#include "langhooks.h"
60393bbc
AM
56#include "dominance.h"
57#include "cfg.h"
58#include "cfgrtl.h"
59#include "cfganal.h"
60#include "lcm.h"
61#include "cfgbuild.h"
62#include "cfgcleanup.h"
63#include "predict.h"
64#include "basic-block.h"
954c7446 65#include "df.h"
9b2b7279 66#include "builtins.h"
6b3d1e47 67
d58627a0
RS
68#include "target-def.h"
69
6b3d1e47
SC
70/* Enumeration for all of the relational tests, so that we can build
71 arrays indexed by the test type, and not worry about the order
72 of EQ, NE, etc. */
73
b5144086
SC
74enum internal_test
75 {
6b3d1e47
SC
76 ITEST_EQ,
77 ITEST_NE,
78 ITEST_GT,
79 ITEST_GE,
80 ITEST_LT,
81 ITEST_LE,
82 ITEST_GTU,
83 ITEST_GEU,
84 ITEST_LTU,
85 ITEST_LEU,
86 ITEST_MAX
87 };
88
89struct constant;
90
6b3d1e47
SC
91\f
92/* Structure to be filled in by compute_frame_size with register
93 save masks, and offsets for the current function. */
94
95struct iq2000_frame_info
96{
b5144086
SC
97 long total_size; /* # bytes that the entire frame takes up. */
98 long var_size; /* # bytes that variables take up. */
99 long args_size; /* # bytes that outgoing arguments take up. */
100 long extra_size; /* # bytes of extra gunk. */
101 int gp_reg_size; /* # bytes needed to store gp regs. */
102 int fp_reg_size; /* # bytes needed to store fp regs. */
103 long mask; /* Mask of saved gp registers. */
104 long gp_save_offset; /* Offset from vfp to store gp registers. */
105 long fp_save_offset; /* Offset from vfp to store fp registers. */
106 long gp_sp_offset; /* Offset from new sp to store gp registers. */
107 long fp_sp_offset; /* Offset from new sp to store fp registers. */
108 int initialized; /* != 0 if frame size already calculated. */
109 int num_gp; /* Number of gp registers saved. */
110} iq2000_frame_info;
111
d1b38208 112struct GTY(()) machine_function
6b3d1e47
SC
113{
114 /* Current frame information, calculated by compute_frame_size. */
b5144086
SC
115 long total_size; /* # bytes that the entire frame takes up. */
116 long var_size; /* # bytes that variables take up. */
117 long args_size; /* # bytes that outgoing arguments take up. */
118 long extra_size; /* # bytes of extra gunk. */
119 int gp_reg_size; /* # bytes needed to store gp regs. */
120 int fp_reg_size; /* # bytes needed to store fp regs. */
121 long mask; /* Mask of saved gp registers. */
122 long gp_save_offset; /* Offset from vfp to store gp registers. */
123 long fp_save_offset; /* Offset from vfp to store fp registers. */
124 long gp_sp_offset; /* Offset from new sp to store gp registers. */
125 long fp_sp_offset; /* Offset from new sp to store fp registers. */
126 int initialized; /* != 0 if frame size already calculated. */
127 int num_gp; /* Number of gp registers saved. */
6b3d1e47
SC
128};
129
130/* Global variables for machine-dependent things. */
131
bf7c1408
NF
132/* List of all IQ2000 punctuation characters used by iq2000_print_operand. */
133static char iq2000_print_operand_punct[256];
6b3d1e47 134
b5144086
SC
135/* Which instruction set architecture to use. */
136int iq2000_isa;
6b3d1e47 137
b5144086 138/* Local variables. */
6b3d1e47 139
b5144086
SC
140/* The next branch instruction is a branch likely, not branch normal. */
141static int iq2000_branch_likely;
142
143/* Count of delay slots and how many are filled. */
144static int dslots_load_total;
145static int dslots_load_filled;
146static int dslots_jump_total;
147
148/* # of nops needed by previous insn. */
149static int dslots_number_nops;
150
112cdef5 151/* Number of 1/2/3 word references to data items (i.e., not jal's). */
b5144086
SC
152static int num_refs[3];
153
154/* Registers to check for load delay. */
155static rtx iq2000_load_reg;
156static rtx iq2000_load_reg2;
157static rtx iq2000_load_reg3;
158static rtx iq2000_load_reg4;
159
6b3d1e47 160/* Mode used for saving/restoring general purpose registers. */
ef4bddc2 161static machine_mode gpr_mode;
6b3d1e47 162
6b3d1e47
SC
163\f
164/* Initialize the GCC target structure. */
b5144086 165static struct machine_function* iq2000_init_machine_status (void);
c5387660 166static void iq2000_option_override (void);
ef4bddc2 167static section *iq2000_select_rtx_section (machine_mode, rtx,
d6b5193b 168 unsigned HOST_WIDE_INT);
b5144086 169static void iq2000_init_builtins (void);
ef4bddc2 170static rtx iq2000_expand_builtin (tree, rtx, rtx, machine_mode, int);
586de218 171static bool iq2000_return_in_memory (const_tree, const_tree);
d5cc9181 172static void iq2000_setup_incoming_varargs (cumulative_args_t,
ef4bddc2 173 machine_mode, tree, int *,
69a45040 174 int);
68f932c4 175static bool iq2000_rtx_costs (rtx, int, int, int, int *, bool);
ef4bddc2 176static int iq2000_address_cost (rtx, machine_mode, addr_space_t,
b413068c 177 bool);
d6b5193b 178static section *iq2000_select_section (tree, int, unsigned HOST_WIDE_INT);
ef4bddc2
RS
179static rtx iq2000_legitimize_address (rtx, rtx, machine_mode);
180static bool iq2000_pass_by_reference (cumulative_args_t, machine_mode,
586de218 181 const_tree, bool);
ef4bddc2 182static int iq2000_arg_partial_bytes (cumulative_args_t, machine_mode,
78a52f11 183 tree, bool);
d5cc9181 184static rtx iq2000_function_arg (cumulative_args_t,
ef4bddc2 185 machine_mode, const_tree, bool);
d5cc9181 186static void iq2000_function_arg_advance (cumulative_args_t,
ef4bddc2
RS
187 machine_mode, const_tree, bool);
188static unsigned int iq2000_function_arg_boundary (machine_mode,
c2ed6cf8 189 const_tree);
d7bd8aeb 190static void iq2000_va_start (tree, rtx);
ef4bddc2 191static bool iq2000_legitimate_address_p (machine_mode, rtx, bool);
7b5cbb57 192static bool iq2000_can_eliminate (const int, const int);
f4a33d37
RH
193static void iq2000_asm_trampoline_template (FILE *);
194static void iq2000_trampoline_init (rtx, tree, rtx);
7ae62237 195static rtx iq2000_function_value (const_tree, const_tree, bool);
ef4bddc2 196static rtx iq2000_libcall_value (machine_mode, const_rtx);
bf7c1408
NF
197static void iq2000_print_operand (FILE *, rtx, int);
198static void iq2000_print_operand_address (FILE *, rtx);
199static bool iq2000_print_operand_punct_valid_p (unsigned char code);
b5144086
SC
200
201#undef TARGET_INIT_BUILTINS
202#define TARGET_INIT_BUILTINS iq2000_init_builtins
203#undef TARGET_EXPAND_BUILTIN
204#define TARGET_EXPAND_BUILTIN iq2000_expand_builtin
205#undef TARGET_ASM_SELECT_RTX_SECTION
206#define TARGET_ASM_SELECT_RTX_SECTION iq2000_select_rtx_section
c5387660
JM
207#undef TARGET_OPTION_OVERRIDE
208#define TARGET_OPTION_OVERRIDE iq2000_option_override
b5144086
SC
209#undef TARGET_RTX_COSTS
210#define TARGET_RTX_COSTS iq2000_rtx_costs
211#undef TARGET_ADDRESS_COST
212#define TARGET_ADDRESS_COST iq2000_address_cost
213#undef TARGET_ASM_SELECT_SECTION
214#define TARGET_ASM_SELECT_SECTION iq2000_select_section
6b3d1e47 215
506d7b68
PB
216#undef TARGET_LEGITIMIZE_ADDRESS
217#define TARGET_LEGITIMIZE_ADDRESS iq2000_legitimize_address
218
434aeebb
RS
219/* The assembler supports switchable .bss sections, but
220 iq2000_select_section doesn't yet make use of them. */
221#undef TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
222#define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
223
bf7c1408
NF
224#undef TARGET_PRINT_OPERAND
225#define TARGET_PRINT_OPERAND iq2000_print_operand
226#undef TARGET_PRINT_OPERAND_ADDRESS
227#define TARGET_PRINT_OPERAND_ADDRESS iq2000_print_operand_address
228#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
229#define TARGET_PRINT_OPERAND_PUNCT_VALID_P iq2000_print_operand_punct_valid_p
230
cde0f3fd
PB
231#undef TARGET_PROMOTE_FUNCTION_MODE
232#define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
69a45040 233#undef TARGET_PROMOTE_PROTOTYPES
586de218 234#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
69a45040 235
7ae62237
AS
236#undef TARGET_FUNCTION_VALUE
237#define TARGET_FUNCTION_VALUE iq2000_function_value
238#undef TARGET_LIBCALL_VALUE
239#define TARGET_LIBCALL_VALUE iq2000_libcall_value
69a45040
KH
240#undef TARGET_RETURN_IN_MEMORY
241#define TARGET_RETURN_IN_MEMORY iq2000_return_in_memory
8cd5a4e0
RH
242#undef TARGET_PASS_BY_REFERENCE
243#define TARGET_PASS_BY_REFERENCE iq2000_pass_by_reference
6cdd5672
RH
244#undef TARGET_CALLEE_COPIES
245#define TARGET_CALLEE_COPIES hook_callee_copies_named
78a52f11
RH
246#undef TARGET_ARG_PARTIAL_BYTES
247#define TARGET_ARG_PARTIAL_BYTES iq2000_arg_partial_bytes
24ef86d7
NF
248#undef TARGET_FUNCTION_ARG
249#define TARGET_FUNCTION_ARG iq2000_function_arg
250#undef TARGET_FUNCTION_ARG_ADVANCE
251#define TARGET_FUNCTION_ARG_ADVANCE iq2000_function_arg_advance
c2ed6cf8
NF
252#undef TARGET_FUNCTION_ARG_BOUNDARY
253#define TARGET_FUNCTION_ARG_BOUNDARY iq2000_function_arg_boundary
69a45040
KH
254
255#undef TARGET_SETUP_INCOMING_VARARGS
256#define TARGET_SETUP_INCOMING_VARARGS iq2000_setup_incoming_varargs
257#undef TARGET_STRICT_ARGUMENT_NAMING
258#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
259
d7bd8aeb
JJ
260#undef TARGET_EXPAND_BUILTIN_VA_START
261#define TARGET_EXPAND_BUILTIN_VA_START iq2000_va_start
262
c6c3dba9
PB
263#undef TARGET_LEGITIMATE_ADDRESS_P
264#define TARGET_LEGITIMATE_ADDRESS_P iq2000_legitimate_address_p
265
7b5cbb57
AS
266#undef TARGET_CAN_ELIMINATE
267#define TARGET_CAN_ELIMINATE iq2000_can_eliminate
268
f4a33d37
RH
269#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
270#define TARGET_ASM_TRAMPOLINE_TEMPLATE iq2000_asm_trampoline_template
271#undef TARGET_TRAMPOLINE_INIT
272#define TARGET_TRAMPOLINE_INIT iq2000_trampoline_init
273
6b3d1e47
SC
274struct gcc_target targetm = TARGET_INITIALIZER;
275\f
6b3d1e47
SC
276/* Return nonzero if we split the address into high and low parts. */
277
278int
ef4bddc2 279iq2000_check_split (rtx address, machine_mode mode)
6b3d1e47
SC
280{
281 /* This is the same check used in simple_memory_operand.
282 We use it here because LO_SUM is not offsettable. */
283 if (GET_MODE_SIZE (mode) > (unsigned) UNITS_PER_WORD)
284 return 0;
285
286 if ((GET_CODE (address) == SYMBOL_REF)
287 || (GET_CODE (address) == CONST
288 && GET_CODE (XEXP (XEXP (address, 0), 0)) == SYMBOL_REF)
289 || GET_CODE (address) == LABEL_REF)
290 return 1;
291
292 return 0;
293}
294
295/* Return nonzero if REG is valid for MODE. */
296
297int
b7849684 298iq2000_reg_mode_ok_for_base_p (rtx reg,
ef4bddc2 299 machine_mode mode ATTRIBUTE_UNUSED,
b7849684 300 int strict)
6b3d1e47
SC
301{
302 return (strict
303 ? REGNO_MODE_OK_FOR_BASE_P (REGNO (reg), mode)
304 : GP_REG_OR_PSEUDO_NONSTRICT_P (REGNO (reg), mode));
305}
306
307/* Return a nonzero value if XINSN is a legitimate address for a
4375e090 308 memory operand of the indicated MODE. STRICT is nonzero if this
6b3d1e47
SC
309 function is called during reload. */
310
c6c3dba9 311bool
ef4bddc2 312iq2000_legitimate_address_p (machine_mode mode, rtx xinsn, bool strict)
6b3d1e47
SC
313{
314 if (TARGET_DEBUG_A_MODE)
315 {
331d9186 316 GO_PRINTF2 ("\n========== legitimate_address_p, %sstrict\n",
6b3d1e47
SC
317 strict ? "" : "not ");
318 GO_DEBUG_RTX (xinsn);
319 }
320
321 /* Check for constant before stripping off SUBREG, so that we don't
322 accept (subreg (const_int)) which will fail to reload. */
323 if (CONSTANT_ADDRESS_P (xinsn)
324 && ! (iq2000_check_split (xinsn, mode))
325 && ! (GET_CODE (xinsn) == CONST_INT && ! SMALL_INT (xinsn)))
326 return 1;
327
328 while (GET_CODE (xinsn) == SUBREG)
329 xinsn = SUBREG_REG (xinsn);
330
331 if (GET_CODE (xinsn) == REG
332 && iq2000_reg_mode_ok_for_base_p (xinsn, mode, strict))
333 return 1;
334
335 if (GET_CODE (xinsn) == LO_SUM)
336 {
b5144086
SC
337 rtx xlow0 = XEXP (xinsn, 0);
338 rtx xlow1 = XEXP (xinsn, 1);
6b3d1e47
SC
339
340 while (GET_CODE (xlow0) == SUBREG)
341 xlow0 = SUBREG_REG (xlow0);
342 if (GET_CODE (xlow0) == REG
343 && iq2000_reg_mode_ok_for_base_p (xlow0, mode, strict)
344 && iq2000_check_split (xlow1, mode))
345 return 1;
346 }
347
348 if (GET_CODE (xinsn) == PLUS)
349 {
b5144086
SC
350 rtx xplus0 = XEXP (xinsn, 0);
351 rtx xplus1 = XEXP (xinsn, 1);
352 enum rtx_code code0;
353 enum rtx_code code1;
6b3d1e47
SC
354
355 while (GET_CODE (xplus0) == SUBREG)
356 xplus0 = SUBREG_REG (xplus0);
357 code0 = GET_CODE (xplus0);
358
359 while (GET_CODE (xplus1) == SUBREG)
360 xplus1 = SUBREG_REG (xplus1);
361 code1 = GET_CODE (xplus1);
362
363 if (code0 == REG
364 && iq2000_reg_mode_ok_for_base_p (xplus0, mode, strict))
365 {
366 if (code1 == CONST_INT && SMALL_INT (xplus1)
367 && SMALL_INT_UNSIGNED (xplus1) /* No negative offsets */)
368 return 1;
369 }
370 }
371
372 if (TARGET_DEBUG_A_MODE)
ef4bddc2 373 GO_PRINTF ("Not a machine_mode mode, legitimate address\n");
6b3d1e47
SC
374
375 /* The address was not legitimate. */
376 return 0;
377}
378\f
379/* Returns an operand string for the given instruction's delay slot,
380 after updating filled delay slot statistics.
381
382 We assume that operands[0] is the target register that is set.
383
384 In order to check the next insn, most of this functionality is moved
385 to FINAL_PRESCAN_INSN, and we just set the global variables that
386 it needs. */
387
388const char *
b7849684 389iq2000_fill_delay_slot (const char *ret, enum delay_type type, rtx operands[],
b32d5189 390 rtx_insn *cur_insn)
6b3d1e47 391{
b5144086 392 rtx set_reg;
ef4bddc2 393 machine_mode mode;
b32d5189 394 rtx_insn *next_insn = cur_insn ? NEXT_INSN (cur_insn) : NULL;
b5144086 395 int num_nops;
6b3d1e47
SC
396
397 if (type == DELAY_LOAD || type == DELAY_FCMP)
398 num_nops = 1;
399
400 else
401 num_nops = 0;
402
403 /* Make sure that we don't put nop's after labels. */
404 next_insn = NEXT_INSN (cur_insn);
405 while (next_insn != 0
b64925dc 406 && (NOTE_P (next_insn) || LABEL_P (next_insn)))
6b3d1e47
SC
407 next_insn = NEXT_INSN (next_insn);
408
409 dslots_load_total += num_nops;
410 if (TARGET_DEBUG_C_MODE
411 || type == DELAY_NONE
412 || operands == 0
413 || cur_insn == 0
414 || next_insn == 0
b64925dc 415 || LABEL_P (next_insn)
6b3d1e47
SC
416 || (set_reg = operands[0]) == 0)
417 {
418 dslots_number_nops = 0;
419 iq2000_load_reg = 0;
420 iq2000_load_reg2 = 0;
421 iq2000_load_reg3 = 0;
422 iq2000_load_reg4 = 0;
b5144086 423
6b3d1e47
SC
424 return ret;
425 }
426
427 set_reg = operands[0];
428 if (set_reg == 0)
429 return ret;
430
431 while (GET_CODE (set_reg) == SUBREG)
432 set_reg = SUBREG_REG (set_reg);
433
434 mode = GET_MODE (set_reg);
435 dslots_number_nops = num_nops;
436 iq2000_load_reg = set_reg;
437 if (GET_MODE_SIZE (mode)
438 > (unsigned) (UNITS_PER_WORD))
439 iq2000_load_reg2 = gen_rtx_REG (SImode, REGNO (set_reg) + 1);
440 else
441 iq2000_load_reg2 = 0;
442
443 return ret;
444}
445\f
446/* Determine whether a memory reference takes one (based off of the GP
447 pointer), two (normal), or three (label + reg) instructions, and bump the
448 appropriate counter for -mstats. */
449
450static void
b7849684 451iq2000_count_memory_refs (rtx op, int num)
6b3d1e47
SC
452{
453 int additional = 0;
454 int n_words = 0;
455 rtx addr, plus0, plus1;
456 enum rtx_code code0, code1;
457 int looping;
458
459 if (TARGET_DEBUG_B_MODE)
460 {
461 fprintf (stderr, "\n========== iq2000_count_memory_refs:\n");
462 debug_rtx (op);
463 }
464
465 /* Skip MEM if passed, otherwise handle movsi of address. */
466 addr = (GET_CODE (op) != MEM) ? op : XEXP (op, 0);
467
468 /* Loop, going through the address RTL. */
469 do
470 {
471 looping = FALSE;
472 switch (GET_CODE (addr))
473 {
474 case REG:
475 case CONST_INT:
476 case LO_SUM:
477 break;
478
479 case PLUS:
480 plus0 = XEXP (addr, 0);
481 plus1 = XEXP (addr, 1);
482 code0 = GET_CODE (plus0);
483 code1 = GET_CODE (plus1);
484
485 if (code0 == REG)
486 {
487 additional++;
488 addr = plus1;
489 looping = 1;
490 continue;
491 }
492
493 if (code0 == CONST_INT)
494 {
495 addr = plus1;
496 looping = 1;
497 continue;
498 }
499
500 if (code1 == REG)
501 {
502 additional++;
503 addr = plus0;
504 looping = 1;
505 continue;
506 }
507
508 if (code1 == CONST_INT)
509 {
510 addr = plus0;
511 looping = 1;
512 continue;
513 }
514
515 if (code0 == SYMBOL_REF || code0 == LABEL_REF || code0 == CONST)
516 {
517 addr = plus0;
518 looping = 1;
519 continue;
520 }
521
522 if (code1 == SYMBOL_REF || code1 == LABEL_REF || code1 == CONST)
523 {
524 addr = plus1;
525 looping = 1;
526 continue;
527 }
528
529 break;
530
531 case LABEL_REF:
b5144086 532 n_words = 2; /* Always 2 words. */
6b3d1e47
SC
533 break;
534
535 case CONST:
536 addr = XEXP (addr, 0);
537 looping = 1;
538 continue;
539
540 case SYMBOL_REF:
541 n_words = SYMBOL_REF_FLAG (addr) ? 1 : 2;
542 break;
543
544 default:
545 break;
546 }
547 }
548 while (looping);
549
550 if (n_words == 0)
551 return;
552
553 n_words += additional;
554 if (n_words > 3)
555 n_words = 3;
556
557 num_refs[n_words-1] += num;
558}
559\f
b5144086
SC
560/* Abort after printing out a specific insn. */
561
562static void
563abort_with_insn (rtx insn, const char * reason)
564{
565 error (reason);
566 debug_rtx (insn);
292c8018 567 fancy_abort (__FILE__, __LINE__, __FUNCTION__);
b5144086
SC
568}
569\f
6b3d1e47
SC
570/* Return the appropriate instructions to move one operand to another. */
571
572const char *
b32d5189 573iq2000_move_1word (rtx operands[], rtx_insn *insn, int unsignedp)
6b3d1e47
SC
574{
575 const char *ret = 0;
576 rtx op0 = operands[0];
577 rtx op1 = operands[1];
578 enum rtx_code code0 = GET_CODE (op0);
579 enum rtx_code code1 = GET_CODE (op1);
ef4bddc2 580 machine_mode mode = GET_MODE (op0);
6b3d1e47
SC
581 int subreg_offset0 = 0;
582 int subreg_offset1 = 0;
583 enum delay_type delay = DELAY_NONE;
584
585 while (code0 == SUBREG)
586 {
587 subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)),
588 GET_MODE (SUBREG_REG (op0)),
589 SUBREG_BYTE (op0),
590 GET_MODE (op0));
591 op0 = SUBREG_REG (op0);
592 code0 = GET_CODE (op0);
593 }
594
595 while (code1 == SUBREG)
596 {
597 subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)),
598 GET_MODE (SUBREG_REG (op1)),
599 SUBREG_BYTE (op1),
600 GET_MODE (op1));
601 op1 = SUBREG_REG (op1);
602 code1 = GET_CODE (op1);
603 }
604
605 /* For our purposes, a condition code mode is the same as SImode. */
606 if (mode == CCmode)
607 mode = SImode;
608
609 if (code0 == REG)
610 {
611 int regno0 = REGNO (op0) + subreg_offset0;
612
613 if (code1 == REG)
614 {
615 int regno1 = REGNO (op1) + subreg_offset1;
616
617 /* Do not do anything for assigning a register to itself */
618 if (regno0 == regno1)
619 ret = "";
620
621 else if (GP_REG_P (regno0))
622 {
623 if (GP_REG_P (regno1))
624 ret = "or\t%0,%%0,%1";
625 }
626
627 }
628
629 else if (code1 == MEM)
630 {
631 delay = DELAY_LOAD;
632
633 if (TARGET_STATS)
634 iq2000_count_memory_refs (op1, 1);
635
636 if (GP_REG_P (regno0))
637 {
638 /* For loads, use the mode of the memory item, instead of the
639 target, so zero/sign extend can use this code as well. */
640 switch (GET_MODE (op1))
641 {
642 default:
643 break;
644 case SFmode:
645 ret = "lw\t%0,%1";
646 break;
647 case SImode:
648 case CCmode:
649 ret = "lw\t%0,%1";
650 break;
651 case HImode:
652 ret = (unsignedp) ? "lhu\t%0,%1" : "lh\t%0,%1";
653 break;
654 case QImode:
655 ret = (unsignedp) ? "lbu\t%0,%1" : "lb\t%0,%1";
656 break;
657 }
658 }
659 }
660
661 else if (code1 == CONST_INT
662 || (code1 == CONST_DOUBLE
663 && GET_MODE (op1) == VOIDmode))
664 {
665 if (code1 == CONST_DOUBLE)
666 {
667 /* This can happen when storing constants into long long
668 bitfields. Just store the least significant word of
669 the value. */
670 operands[1] = op1 = GEN_INT (CONST_DOUBLE_LOW (op1));
671 }
672
673 if (INTVAL (op1) == 0)
674 {
675 if (GP_REG_P (regno0))
676 ret = "or\t%0,%%0,%z1";
677 }
678 else if (GP_REG_P (regno0))
679 {
680 if (SMALL_INT_UNSIGNED (op1))
681 ret = "ori\t%0,%%0,%x1\t\t\t# %1";
682 else if (SMALL_INT (op1))
683 ret = "addiu\t%0,%%0,%1\t\t\t# %1";
684 else
685 ret = "lui\t%0,%X1\t\t\t# %1\n\tori\t%0,%0,%x1";
686 }
687 }
688
689 else if (code1 == CONST_DOUBLE && mode == SFmode)
690 {
691 if (op1 == CONST0_RTX (SFmode))
692 {
693 if (GP_REG_P (regno0))
694 ret = "or\t%0,%%0,%.";
695 }
696
697 else
698 {
699 delay = DELAY_LOAD;
700 ret = "li.s\t%0,%1";
701 }
702 }
703
704 else if (code1 == LABEL_REF)
705 {
706 if (TARGET_STATS)
707 iq2000_count_memory_refs (op1, 1);
708
709 ret = "la\t%0,%a1";
710 }
711
712 else if (code1 == SYMBOL_REF || code1 == CONST)
713 {
714 if (TARGET_STATS)
715 iq2000_count_memory_refs (op1, 1);
716
717 ret = "la\t%0,%a1";
718 }
719
720 else if (code1 == PLUS)
721 {
722 rtx add_op0 = XEXP (op1, 0);
723 rtx add_op1 = XEXP (op1, 1);
724
725 if (GET_CODE (XEXP (op1, 1)) == REG
726 && GET_CODE (XEXP (op1, 0)) == CONST_INT)
727 add_op0 = XEXP (op1, 1), add_op1 = XEXP (op1, 0);
728
729 operands[2] = add_op0;
730 operands[3] = add_op1;
731 ret = "add%:\t%0,%2,%3";
732 }
733
734 else if (code1 == HIGH)
735 {
736 operands[1] = XEXP (op1, 0);
737 ret = "lui\t%0,%%hi(%1)";
738 }
739 }
740
741 else if (code0 == MEM)
742 {
743 if (TARGET_STATS)
744 iq2000_count_memory_refs (op0, 1);
745
746 if (code1 == REG)
747 {
748 int regno1 = REGNO (op1) + subreg_offset1;
749
750 if (GP_REG_P (regno1))
751 {
752 switch (mode)
753 {
754 case SFmode: ret = "sw\t%1,%0"; break;
755 case SImode: ret = "sw\t%1,%0"; break;
756 case HImode: ret = "sh\t%1,%0"; break;
757 case QImode: ret = "sb\t%1,%0"; break;
758 default: break;
759 }
760 }
761 }
762
763 else if (code1 == CONST_INT && INTVAL (op1) == 0)
764 {
765 switch (mode)
766 {
767 case SFmode: ret = "sw\t%z1,%0"; break;
768 case SImode: ret = "sw\t%z1,%0"; break;
769 case HImode: ret = "sh\t%z1,%0"; break;
770 case QImode: ret = "sb\t%z1,%0"; break;
771 default: break;
772 }
773 }
774
775 else if (code1 == CONST_DOUBLE && op1 == CONST0_RTX (mode))
776 {
777 switch (mode)
778 {
779 case SFmode: ret = "sw\t%.,%0"; break;
780 case SImode: ret = "sw\t%.,%0"; break;
781 case HImode: ret = "sh\t%.,%0"; break;
782 case QImode: ret = "sb\t%.,%0"; break;
783 default: break;
784 }
785 }
786 }
787
788 if (ret == 0)
789 {
790 abort_with_insn (insn, "Bad move");
791 return 0;
792 }
793
794 if (delay != DELAY_NONE)
795 return iq2000_fill_delay_slot (ret, delay, operands, insn);
796
797 return ret;
798}
799\f
800/* Provide the costs of an addressing mode that contains ADDR. */
801
b5144086 802static int
ef4bddc2 803iq2000_address_cost (rtx addr, machine_mode mode, addr_space_t as,
b413068c 804 bool speed)
6b3d1e47
SC
805{
806 switch (GET_CODE (addr))
807 {
808 case LO_SUM:
809 return 1;
810
811 case LABEL_REF:
812 return 2;
813
814 case CONST:
815 {
816 rtx offset = const0_rtx;
b5144086
SC
817
818 addr = eliminate_constant_term (XEXP (addr, 0), & offset);
6b3d1e47
SC
819 if (GET_CODE (addr) == LABEL_REF)
820 return 2;
821
822 if (GET_CODE (addr) != SYMBOL_REF)
823 return 4;
824
825 if (! SMALL_INT (offset))
826 return 2;
827 }
828
b5144086 829 /* Fall through. */
6b3d1e47
SC
830
831 case SYMBOL_REF:
832 return SYMBOL_REF_FLAG (addr) ? 1 : 2;
833
834 case PLUS:
835 {
b5144086
SC
836 rtx plus0 = XEXP (addr, 0);
837 rtx plus1 = XEXP (addr, 1);
6b3d1e47
SC
838
839 if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG)
840 plus0 = XEXP (addr, 1), plus1 = XEXP (addr, 0);
841
842 if (GET_CODE (plus0) != REG)
843 break;
844
845 switch (GET_CODE (plus1))
846 {
847 case CONST_INT:
848 return SMALL_INT (plus1) ? 1 : 2;
849
850 case CONST:
851 case SYMBOL_REF:
852 case LABEL_REF:
853 case HIGH:
854 case LO_SUM:
b413068c 855 return iq2000_address_cost (plus1, mode, as, speed) + 1;
6b3d1e47
SC
856
857 default:
858 break;
859 }
860 }
861
862 default:
863 break;
864 }
865
866 return 4;
867}
868\f
869/* Make normal rtx_code into something we can index from an array. */
870
871static enum internal_test
b7849684 872map_test_to_internal_test (enum rtx_code test_code)
6b3d1e47
SC
873{
874 enum internal_test test = ITEST_MAX;
875
876 switch (test_code)
877 {
878 case EQ: test = ITEST_EQ; break;
879 case NE: test = ITEST_NE; break;
880 case GT: test = ITEST_GT; break;
881 case GE: test = ITEST_GE; break;
882 case LT: test = ITEST_LT; break;
883 case LE: test = ITEST_LE; break;
884 case GTU: test = ITEST_GTU; break;
885 case GEU: test = ITEST_GEU; break;
886 case LTU: test = ITEST_LTU; break;
887 case LEU: test = ITEST_LEU; break;
888 default: break;
889 }
890
891 return test;
892}
893\f
b5144086
SC
894/* Generate the code to do a TEST_CODE comparison on two integer values CMP0
895 and CMP1. P_INVERT is NULL or ptr if branch needs to reverse its test.
896 The return value RESULT is:
6b3d1e47 897 (reg:SI xx) The pseudo register the comparison is in
b5144086 898 0 No register, generate a simple branch. */
6b3d1e47
SC
899
900rtx
b7849684
JE
901gen_int_relational (enum rtx_code test_code, rtx result, rtx cmp0, rtx cmp1,
902 int *p_invert)
6b3d1e47
SC
903{
904 struct cmp_info
905 {
b5144086
SC
906 enum rtx_code test_code; /* Code to use in instruction (LT vs. LTU). */
907 int const_low; /* Low bound of constant we can accept. */
908 int const_high; /* High bound of constant we can accept. */
909 int const_add; /* Constant to add (convert LE -> LT). */
910 int reverse_regs; /* Reverse registers in test. */
911 int invert_const; /* != 0 if invert value if cmp1 is constant. */
912 int invert_reg; /* != 0 if invert value if cmp1 is register. */
6b3d1e47
SC
913 int unsignedp; /* != 0 for unsigned comparisons. */
914 };
915
b5144086
SC
916 static struct cmp_info info[ (int)ITEST_MAX ] =
917 {
6b3d1e47
SC
918 { XOR, 0, 65535, 0, 0, 0, 0, 0 }, /* EQ */
919 { XOR, 0, 65535, 0, 0, 1, 1, 0 }, /* NE */
920 { LT, -32769, 32766, 1, 1, 1, 0, 0 }, /* GT */
921 { LT, -32768, 32767, 0, 0, 1, 1, 0 }, /* GE */
922 { LT, -32768, 32767, 0, 0, 0, 0, 0 }, /* LT */
923 { LT, -32769, 32766, 1, 1, 0, 1, 0 }, /* LE */
924 { LTU, -32769, 32766, 1, 1, 1, 0, 1 }, /* GTU */
925 { LTU, -32768, 32767, 0, 0, 1, 1, 1 }, /* GEU */
926 { LTU, -32768, 32767, 0, 0, 0, 0, 1 }, /* LTU */
927 { LTU, -32769, 32766, 1, 1, 0, 1, 1 }, /* LEU */
928 };
929
930 enum internal_test test;
ef4bddc2 931 machine_mode mode;
6b3d1e47
SC
932 struct cmp_info *p_info;
933 int branch_p;
934 int eqne_p;
935 int invert;
936 rtx reg;
937 rtx reg2;
938
939 test = map_test_to_internal_test (test_code);
292c8018 940 gcc_assert (test != ITEST_MAX);
6b3d1e47
SC
941
942 p_info = &info[(int) test];
943 eqne_p = (p_info->test_code == XOR);
944
945 mode = GET_MODE (cmp0);
946 if (mode == VOIDmode)
947 mode = GET_MODE (cmp1);
948
b5144086 949 /* Eliminate simple branches. */
6b3d1e47
SC
950 branch_p = (result == 0);
951 if (branch_p)
952 {
953 if (GET_CODE (cmp0) == REG || GET_CODE (cmp0) == SUBREG)
954 {
b5144086 955 /* Comparisons against zero are simple branches. */
6b3d1e47
SC
956 if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0)
957 return 0;
958
959 /* Test for beq/bne. */
960 if (eqne_p)
961 return 0;
962 }
963
b5144086 964 /* Allocate a pseudo to calculate the value in. */
6b3d1e47
SC
965 result = gen_reg_rtx (mode);
966 }
967
968 /* Make sure we can handle any constants given to us. */
969 if (GET_CODE (cmp0) == CONST_INT)
970 cmp0 = force_reg (mode, cmp0);
971
972 if (GET_CODE (cmp1) == CONST_INT)
973 {
974 HOST_WIDE_INT value = INTVAL (cmp1);
975
976 if (value < p_info->const_low
977 || value > p_info->const_high)
978 cmp1 = force_reg (mode, cmp1);
979 }
980
981 /* See if we need to invert the result. */
982 invert = (GET_CODE (cmp1) == CONST_INT
983 ? p_info->invert_const : p_info->invert_reg);
984
985 if (p_invert != (int *)0)
986 {
987 *p_invert = invert;
988 invert = 0;
989 }
990
991 /* Comparison to constants, may involve adding 1 to change a LT into LE.
992 Comparison between two registers, may involve switching operands. */
993 if (GET_CODE (cmp1) == CONST_INT)
994 {
995 if (p_info->const_add != 0)
996 {
0a2aaacc 997 HOST_WIDE_INT new_const = INTVAL (cmp1) + p_info->const_add;
6b3d1e47
SC
998
999 /* If modification of cmp1 caused overflow,
1000 we would get the wrong answer if we follow the usual path;
1001 thus, x > 0xffffffffU would turn into x > 0U. */
1002 if ((p_info->unsignedp
0a2aaacc 1003 ? (unsigned HOST_WIDE_INT) new_const >
6b3d1e47 1004 (unsigned HOST_WIDE_INT) INTVAL (cmp1)
0a2aaacc 1005 : new_const > INTVAL (cmp1))
6b3d1e47
SC
1006 != (p_info->const_add > 0))
1007 {
1008 /* This test is always true, but if INVERT is true then
1009 the result of the test needs to be inverted so 0 should
1010 be returned instead. */
1011 emit_move_insn (result, invert ? const0_rtx : const_true_rtx);
1012 return result;
1013 }
1014 else
0a2aaacc 1015 cmp1 = GEN_INT (new_const);
6b3d1e47
SC
1016 }
1017 }
1018
1019 else if (p_info->reverse_regs)
1020 {
1021 rtx temp = cmp0;
1022 cmp0 = cmp1;
1023 cmp1 = temp;
1024 }
1025
1026 if (test == ITEST_NE && GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0)
1027 reg = cmp0;
1028 else
1029 {
1030 reg = (invert || eqne_p) ? gen_reg_rtx (mode) : result;
1c563bed 1031 convert_move (reg, gen_rtx_fmt_ee (p_info->test_code, mode, cmp0, cmp1), 0);
6b3d1e47
SC
1032 }
1033
1034 if (test == ITEST_NE)
1035 {
f1c25d3b 1036 convert_move (result, gen_rtx_GTU (mode, reg, const0_rtx), 0);
6b3d1e47
SC
1037 if (p_invert != NULL)
1038 *p_invert = 0;
1039 invert = 0;
1040 }
1041
1042 else if (test == ITEST_EQ)
1043 {
1044 reg2 = invert ? gen_reg_rtx (mode) : result;
1045 convert_move (reg2, gen_rtx_LTU (mode, reg, const1_rtx), 0);
1046 reg = reg2;
1047 }
1048
1049 if (invert)
1050 {
1051 rtx one;
1052
1053 one = const1_rtx;
f1c25d3b 1054 convert_move (result, gen_rtx_XOR (mode, reg, one), 0);
6b3d1e47
SC
1055 }
1056
1057 return result;
1058}
1059\f
1060/* Emit the common code for doing conditional branches.
1061 operand[0] is the label to jump to.
1062 The comparison operands are saved away by cmp{si,di,sf,df}. */
1063
1064void
ef4bddc2 1065gen_conditional_branch (rtx operands[], machine_mode mode)
6b3d1e47 1066{
f90b7a5a
PB
1067 enum rtx_code test_code = GET_CODE (operands[0]);
1068 rtx cmp0 = operands[1];
1069 rtx cmp1 = operands[2];
6b3d1e47
SC
1070 rtx reg;
1071 int invert;
1072 rtx label1, label2;
1073
f90b7a5a
PB
1074 invert = 0;
1075 reg = gen_int_relational (test_code, NULL_RTX, cmp0, cmp1, &invert);
6b3d1e47 1076
f90b7a5a
PB
1077 if (reg)
1078 {
6b3d1e47
SC
1079 cmp0 = reg;
1080 cmp1 = const0_rtx;
f90b7a5a 1081 test_code = NE;
6b3d1e47 1082 }
f90b7a5a
PB
1083 else if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0)
1084 /* We don't want to build a comparison against a nonzero
1085 constant. */
1086 cmp1 = force_reg (mode, cmp1);
6b3d1e47
SC
1087
1088 /* Generate the branch. */
f90b7a5a 1089 label1 = gen_rtx_LABEL_REF (VOIDmode, operands[3]);
6b3d1e47
SC
1090 label2 = pc_rtx;
1091
1092 if (invert)
1093 {
1094 label2 = label1;
1095 label1 = pc_rtx;
1096 }
1097
f7df4a84 1098 emit_jump_insn (gen_rtx_SET (pc_rtx,
6b3d1e47 1099 gen_rtx_IF_THEN_ELSE (VOIDmode,
0f4c242b 1100 gen_rtx_fmt_ee (test_code,
335db8e6 1101 VOIDmode,
0f4c242b 1102 cmp0, cmp1),
6b3d1e47
SC
1103 label1, label2)));
1104}
1105\f
b5144086 1106/* Initialize CUM for a function FNTYPE. */
6b3d1e47
SC
1107
1108void
b7849684
JE
1109init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
1110 rtx libname ATTRIBUTE_UNUSED)
6b3d1e47
SC
1111{
1112 static CUMULATIVE_ARGS zero_cum;
b5144086
SC
1113 tree param;
1114 tree next_param;
6b3d1e47
SC
1115
1116 if (TARGET_DEBUG_D_MODE)
1117 {
1118 fprintf (stderr,
b5144086 1119 "\ninit_cumulative_args, fntype = 0x%.8lx", (long) fntype);
6b3d1e47
SC
1120
1121 if (!fntype)
1122 fputc ('\n', stderr);
1123
1124 else
1125 {
1126 tree ret_type = TREE_TYPE (fntype);
b5144086 1127
6b3d1e47 1128 fprintf (stderr, ", fntype code = %s, ret code = %s\n",
5806f481
PM
1129 get_tree_code_name (TREE_CODE (fntype)),
1130 get_tree_code_name (TREE_CODE (ret_type)));
6b3d1e47
SC
1131 }
1132 }
1133
1134 *cum = zero_cum;
1135
1136 /* Determine if this function has variable arguments. This is
1137 indicated by the last argument being 'void_type_mode' if there
1138 are no variable arguments. The standard IQ2000 calling sequence
1139 passes all arguments in the general purpose registers in this case. */
1140
1141 for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
1142 param != 0; param = next_param)
1143 {
1144 next_param = TREE_CHAIN (param);
1145 if (next_param == 0 && TREE_VALUE (param) != void_type_node)
1146 cum->gp_reg_found = 1;
1147 }
1148}
1149
b5144086
SC
1150/* Advance the argument of type TYPE and mode MODE to the next argument
1151 position in CUM. */
6b3d1e47 1152
24ef86d7 1153static void
ef4bddc2 1154iq2000_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
24ef86d7 1155 const_tree type, bool named)
6b3d1e47 1156{
d5cc9181
JR
1157 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1158
6b3d1e47
SC
1159 if (TARGET_DEBUG_D_MODE)
1160 {
1161 fprintf (stderr,
1162 "function_adv({gp reg found = %d, arg # = %2d, words = %2d}, %4s, ",
1163 cum->gp_reg_found, cum->arg_number, cum->arg_words,
1164 GET_MODE_NAME (mode));
2dc34a12 1165 fprintf (stderr, "%p", (const void *) type);
6b3d1e47
SC
1166 fprintf (stderr, ", %d )\n\n", named);
1167 }
1168
1169 cum->arg_number++;
1170 switch (mode)
1171 {
1172 case VOIDmode:
1173 break;
1174
1175 default:
292c8018
NS
1176 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1177 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
6b3d1e47
SC
1178
1179 cum->gp_reg_found = 1;
1180 cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
1181 / UNITS_PER_WORD);
1182 break;
1183
1184 case BLKmode:
1185 cum->gp_reg_found = 1;
1186 cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1187 / UNITS_PER_WORD);
1188 break;
1189
1190 case SFmode:
b5144086 1191 cum->arg_words ++;
6b3d1e47
SC
1192 if (! cum->gp_reg_found && cum->arg_number <= 2)
1193 cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
1194 break;
1195
1196 case DFmode:
1197 cum->arg_words += 2;
1198 if (! cum->gp_reg_found && cum->arg_number <= 2)
1199 cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
1200 break;
1201
1202 case DImode:
1203 cum->gp_reg_found = 1;
1204 cum->arg_words += 2;
1205 break;
1206
ac4fc08a
NC
1207 case TImode:
1208 cum->gp_reg_found = 1;
1209 cum->arg_words += 4;
1210 break;
1211
6b3d1e47
SC
1212 case QImode:
1213 case HImode:
1214 case SImode:
1215 cum->gp_reg_found = 1;
b5144086 1216 cum->arg_words ++;
6b3d1e47
SC
1217 break;
1218 }
1219}
1220
b5144086
SC
1221/* Return an RTL expression containing the register for the given mode MODE
1222 and type TYPE in CUM, or 0 if the argument is to be passed on the stack. */
6b3d1e47 1223
24ef86d7 1224static rtx
ef4bddc2 1225iq2000_function_arg (cumulative_args_t cum_v, machine_mode mode,
24ef86d7 1226 const_tree type, bool named)
6b3d1e47 1227{
d5cc9181 1228 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
6b3d1e47
SC
1229 rtx ret;
1230 int regbase = -1;
1231 int bias = 0;
1232 unsigned int *arg_words = &cum->arg_words;
1233 int struct_p = (type != 0
1234 && (TREE_CODE (type) == RECORD_TYPE
1235 || TREE_CODE (type) == UNION_TYPE
1236 || TREE_CODE (type) == QUAL_UNION_TYPE));
1237
1238 if (TARGET_DEBUG_D_MODE)
1239 {
1240 fprintf (stderr,
1241 "function_arg( {gp reg found = %d, arg # = %2d, words = %2d}, %4s, ",
1242 cum->gp_reg_found, cum->arg_number, cum->arg_words,
1243 GET_MODE_NAME (mode));
586de218 1244 fprintf (stderr, "%p", (const void *) type);
6b3d1e47
SC
1245 fprintf (stderr, ", %d ) = ", named);
1246 }
1247
1248
1249 cum->last_arg_fp = 0;
1250 switch (mode)
1251 {
1252 case SFmode:
1253 regbase = GP_ARG_FIRST;
1254 break;
1255
1256 case DFmode:
1257 cum->arg_words += cum->arg_words & 1;
1258
1259 regbase = GP_ARG_FIRST;
1260 break;
1261
1262 default:
292c8018
NS
1263 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1264 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
6b3d1e47
SC
1265
1266 /* Drops through. */
1267 case BLKmode:
1268 if (type != NULL_TREE && TYPE_ALIGN (type) > (unsigned) BITS_PER_WORD)
1269 cum->arg_words += (cum->arg_words & 1);
1270 regbase = GP_ARG_FIRST;
1271 break;
1272
1273 case VOIDmode:
1274 case QImode:
1275 case HImode:
1276 case SImode:
1277 regbase = GP_ARG_FIRST;
1278 break;
1279
1280 case DImode:
1281 cum->arg_words += (cum->arg_words & 1);
1282 regbase = GP_ARG_FIRST;
ac4fc08a
NC
1283 break;
1284
1285 case TImode:
1286 cum->arg_words += (cum->arg_words & 3);
1287 regbase = GP_ARG_FIRST;
1288 break;
6b3d1e47
SC
1289 }
1290
1291 if (*arg_words >= (unsigned) MAX_ARGS_IN_REGISTERS)
1292 {
1293 if (TARGET_DEBUG_D_MODE)
1294 fprintf (stderr, "<stack>%s\n", struct_p ? ", [struct]" : "");
1295
1296 ret = 0;
1297 }
1298 else
1299 {
292c8018 1300 gcc_assert (regbase != -1);
6b3d1e47
SC
1301
1302 if (! type || TREE_CODE (type) != RECORD_TYPE
1303 || ! named || ! TYPE_SIZE_UNIT (type)
cc269bb6 1304 || ! tree_fits_uhwi_p (TYPE_SIZE_UNIT (type)))
6b3d1e47
SC
1305 ret = gen_rtx_REG (mode, regbase + *arg_words + bias);
1306 else
1307 {
1308 tree field;
1309
910ad8de 1310 for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
6b3d1e47
SC
1311 if (TREE_CODE (field) == FIELD_DECL
1312 && TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
1313 && TYPE_PRECISION (TREE_TYPE (field)) == BITS_PER_WORD
9541ffee 1314 && tree_fits_shwi_p (bit_position (field))
6b3d1e47
SC
1315 && int_bit_position (field) % BITS_PER_WORD == 0)
1316 break;
1317
1318 /* If the whole struct fits a DFmode register,
1319 we don't need the PARALLEL. */
1320 if (! field || mode == DFmode)
1321 ret = gen_rtx_REG (mode, regbase + *arg_words + bias);
1322 else
1323 {
1324 unsigned int chunks;
1325 HOST_WIDE_INT bitpos;
1326 unsigned int regno;
1327 unsigned int i;
1328
1329 /* ??? If this is a packed structure, then the last hunk won't
1330 be 64 bits. */
6b3d1e47 1331 chunks
ae7e9ddd 1332 = tree_to_uhwi (TYPE_SIZE_UNIT (type)) / UNITS_PER_WORD;
6b3d1e47
SC
1333 if (chunks + *arg_words + bias > (unsigned) MAX_ARGS_IN_REGISTERS)
1334 chunks = MAX_ARGS_IN_REGISTERS - *arg_words - bias;
1335
b5144086 1336 /* Assign_parms checks the mode of ENTRY_PARM, so we must
6b3d1e47
SC
1337 use the actual mode here. */
1338 ret = gen_rtx_PARALLEL (mode, rtvec_alloc (chunks));
1339
1340 bitpos = 0;
1341 regno = regbase + *arg_words + bias;
1342 field = TYPE_FIELDS (type);
1343 for (i = 0; i < chunks; i++)
1344 {
1345 rtx reg;
1346
910ad8de 1347 for (; field; field = DECL_CHAIN (field))
6b3d1e47
SC
1348 if (TREE_CODE (field) == FIELD_DECL
1349 && int_bit_position (field) >= bitpos)
1350 break;
1351
1352 if (field
1353 && int_bit_position (field) == bitpos
1354 && TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
1355 && TYPE_PRECISION (TREE_TYPE (field)) == BITS_PER_WORD)
1356 reg = gen_rtx_REG (DFmode, regno++);
1357 else
1358 reg = gen_rtx_REG (word_mode, regno);
1359
1360 XVECEXP (ret, 0, i)
1361 = gen_rtx_EXPR_LIST (VOIDmode, reg,
1362 GEN_INT (bitpos / BITS_PER_UNIT));
1363
1364 bitpos += 64;
1365 regno++;
1366 }
1367 }
1368 }
1369
1370 if (TARGET_DEBUG_D_MODE)
1371 fprintf (stderr, "%s%s\n", reg_names[regbase + *arg_words + bias],
1372 struct_p ? ", [struct]" : "");
1373 }
1374
1375 /* We will be called with a mode of VOIDmode after the last argument
1376 has been seen. Whatever we return will be passed to the call
1377 insn. If we need any shifts for small structures, return them in
1378 a PARALLEL. */
1379 if (mode == VOIDmode)
1380 {
1381 if (cum->num_adjusts > 0)
ef4bddc2 1382 ret = gen_rtx_PARALLEL ((machine_mode) cum->fp_code,
6b3d1e47
SC
1383 gen_rtvec_v (cum->num_adjusts, cum->adjust));
1384 }
1385
1386 return ret;
1387}
1388
c2ed6cf8 1389static unsigned int
ef4bddc2 1390iq2000_function_arg_boundary (machine_mode mode, const_tree type)
c2ed6cf8
NF
1391{
1392 return (type != NULL_TREE
1393 ? (TYPE_ALIGN (type) <= PARM_BOUNDARY
1394 ? PARM_BOUNDARY
1395 : TYPE_ALIGN (type))
1396 : (GET_MODE_ALIGNMENT (mode) <= PARM_BOUNDARY
1397 ? PARM_BOUNDARY
1398 : GET_MODE_ALIGNMENT (mode)));
1399}
1400
78a52f11 1401static int
ef4bddc2 1402iq2000_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
78a52f11
RH
1403 tree type ATTRIBUTE_UNUSED,
1404 bool named ATTRIBUTE_UNUSED)
6b3d1e47 1405{
d5cc9181
JR
1406 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1407
78a52f11 1408 if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1)
6b3d1e47
SC
1409 {
1410 if (TARGET_DEBUG_D_MODE)
78a52f11
RH
1411 fprintf (stderr, "iq2000_arg_partial_bytes=%d\n", UNITS_PER_WORD);
1412 return UNITS_PER_WORD;
6b3d1e47
SC
1413 }
1414
1415 return 0;
1416}
1417\f
1418/* Implement va_start. */
1419
d7bd8aeb 1420static void
b7849684 1421iq2000_va_start (tree valist, rtx nextarg)
6b3d1e47
SC
1422{
1423 int int_arg_words;
b5144086 1424 /* Find out how many non-float named formals. */
6b3d1e47 1425 int gpr_save_area_size;
b5144086 1426 /* Note UNITS_PER_WORD is 4 bytes. */
38173d38 1427 int_arg_words = crtl->args.info.arg_words;
b5144086 1428
6b3d1e47 1429 if (int_arg_words < 8 )
b5144086 1430 /* Adjust for the prologue's economy measure. */
6b3d1e47
SC
1431 gpr_save_area_size = (8 - int_arg_words) * UNITS_PER_WORD;
1432 else
1433 gpr_save_area_size = 0;
1434
1435 /* Everything is in the GPR save area, or in the overflow
1436 area which is contiguous with it. */
0a81f074 1437 nextarg = plus_constant (Pmode, nextarg, - gpr_save_area_size);
6b3d1e47
SC
1438 std_expand_builtin_va_start (valist, nextarg);
1439}
6b3d1e47 1440\f
b5144086 1441/* Allocate a chunk of memory for per-function machine-dependent data. */
6b3d1e47 1442
b5144086
SC
1443static struct machine_function *
1444iq2000_init_machine_status (void)
6b3d1e47 1445{
766090c2 1446 return ggc_cleared_alloc<machine_function> ();
6b3d1e47 1447}
b5144086 1448
6b3d1e47
SC
1449/* Detect any conflicts in the switches. */
1450
c5387660
JM
1451static void
1452iq2000_option_override (void)
6b3d1e47 1453{
6b3d1e47
SC
1454 target_flags &= ~MASK_GPOPT;
1455
1456 iq2000_isa = IQ2000_ISA_DEFAULT;
1457
1458 /* Identify the processor type. */
1459
6b3d1e47
SC
1460 iq2000_print_operand_punct['?'] = 1;
1461 iq2000_print_operand_punct['#'] = 1;
1462 iq2000_print_operand_punct['&'] = 1;
1463 iq2000_print_operand_punct['!'] = 1;
1464 iq2000_print_operand_punct['*'] = 1;
1465 iq2000_print_operand_punct['@'] = 1;
1466 iq2000_print_operand_punct['.'] = 1;
1467 iq2000_print_operand_punct['('] = 1;
1468 iq2000_print_operand_punct[')'] = 1;
1469 iq2000_print_operand_punct['['] = 1;
1470 iq2000_print_operand_punct[']'] = 1;
1471 iq2000_print_operand_punct['<'] = 1;
1472 iq2000_print_operand_punct['>'] = 1;
1473 iq2000_print_operand_punct['{'] = 1;
1474 iq2000_print_operand_punct['}'] = 1;
1475 iq2000_print_operand_punct['^'] = 1;
1476 iq2000_print_operand_punct['$'] = 1;
1477 iq2000_print_operand_punct['+'] = 1;
1478 iq2000_print_operand_punct['~'] = 1;
1479
1480 /* Save GPR registers in word_mode sized hunks. word_mode hasn't been
1481 initialized yet, so we can't use that here. */
1482 gpr_mode = SImode;
1483
1484 /* Function to allocate machine-dependent function status. */
b5144086 1485 init_machine_status = iq2000_init_machine_status;
6b3d1e47
SC
1486}
1487\f
1488/* The arg pointer (which is eliminated) points to the virtual frame pointer,
1489 while the frame pointer (which may be eliminated) points to the stack
1490 pointer after the initial adjustments. */
1491
1492HOST_WIDE_INT
b7849684 1493iq2000_debugger_offset (rtx addr, HOST_WIDE_INT offset)
6b3d1e47
SC
1494{
1495 rtx offset2 = const0_rtx;
b5144086 1496 rtx reg = eliminate_constant_term (addr, & offset2);
6b3d1e47
SC
1497
1498 if (offset == 0)
1499 offset = INTVAL (offset2);
1500
1501 if (reg == stack_pointer_rtx || reg == frame_pointer_rtx
1502 || reg == hard_frame_pointer_rtx)
1503 {
b5144086 1504 HOST_WIDE_INT frame_size = (!cfun->machine->initialized)
6b3d1e47 1505 ? compute_frame_size (get_frame_size ())
b5144086 1506 : cfun->machine->total_size;
6b3d1e47
SC
1507
1508 offset = offset - frame_size;
1509 }
1510
1511 return offset;
1512}
1513\f
1514/* If defined, a C statement to be executed just prior to the output of
1515 assembler code for INSN, to modify the extracted operands so they will be
1516 output differently.
1517
1518 Here the argument OPVEC is the vector containing the operands extracted
1519 from INSN, and NOPERANDS is the number of elements of the vector which
1520 contain meaningful data for this insn. The contents of this vector are
1521 what will be used to convert the insn template into assembler code, so you
1522 can change the assembler output by changing the contents of the vector.
1523
1524 We use it to check if the current insn needs a nop in front of it because
1525 of load delays, and also to update the delay slot statistics. */
1526
1527void
6ae94a0b 1528final_prescan_insn (rtx_insn *insn, rtx opvec[] ATTRIBUTE_UNUSED,
b7849684 1529 int noperands ATTRIBUTE_UNUSED)
6b3d1e47
SC
1530{
1531 if (dslots_number_nops > 0)
1532 {
1533 rtx pattern = PATTERN (insn);
1534 int length = get_attr_length (insn);
1535
b5144086 1536 /* Do we need to emit a NOP? */
6b3d1e47
SC
1537 if (length == 0
1538 || (iq2000_load_reg != 0 && reg_mentioned_p (iq2000_load_reg, pattern))
1539 || (iq2000_load_reg2 != 0 && reg_mentioned_p (iq2000_load_reg2, pattern))
1540 || (iq2000_load_reg3 != 0 && reg_mentioned_p (iq2000_load_reg3, pattern))
1541 || (iq2000_load_reg4 != 0
1542 && reg_mentioned_p (iq2000_load_reg4, pattern)))
1543 fputs ("\tnop\n", asm_out_file);
1544
1545 else
b5144086 1546 dslots_load_filled ++;
6b3d1e47
SC
1547
1548 while (--dslots_number_nops > 0)
1549 fputs ("\tnop\n", asm_out_file);
1550
1551 iq2000_load_reg = 0;
1552 iq2000_load_reg2 = 0;
1553 iq2000_load_reg3 = 0;
1554 iq2000_load_reg4 = 0;
1555 }
1556
b64925dc
SB
1557 if ( (JUMP_P (insn)
1558 || CALL_P (insn)
6b3d1e47
SC
1559 || (GET_CODE (PATTERN (insn)) == RETURN))
1560 && NEXT_INSN (PREV_INSN (insn)) == insn)
1561 {
6ae94a0b 1562 rtx_insn *nop_insn = emit_insn_after (gen_nop (), insn);
b5144086 1563
6b3d1e47
SC
1564 INSN_ADDRESSES_NEW (nop_insn, -1);
1565 }
1566
1567 if (TARGET_STATS
b64925dc 1568 && (JUMP_P (insn) || CALL_P (insn)))
b5144086 1569 dslots_jump_total ++;
6b3d1e47
SC
1570}
1571\f
1572/* Return the bytes needed to compute the frame pointer from the current
b5144086 1573 stack pointer where SIZE is the # of var. bytes allocated.
6b3d1e47
SC
1574
1575 IQ2000 stack frames look like:
1576
1577 Before call After call
1578 +-----------------------+ +-----------------------+
1579 high | | | |
1580 mem. | | | |
1581 | caller's temps. | | caller's temps. |
1582 | | | |
1583 +-----------------------+ +-----------------------+
1584 | | | |
1585 | arguments on stack. | | arguments on stack. |
1586 | | | |
1587 +-----------------------+ +-----------------------+
1588 | 4 words to save | | 4 words to save |
1589 | arguments passed | | arguments passed |
1590 | in registers, even | | in registers, even |
1591 SP->| if not passed. | VFP->| if not passed. |
1592 +-----------------------+ +-----------------------+
1593 | |
1594 | fp register save |
1595 | |
1596 +-----------------------+
1597 | |
1598 | gp register save |
1599 | |
1600 +-----------------------+
1601 | |
1602 | local variables |
1603 | |
1604 +-----------------------+
1605 | |
1606 | alloca allocations |
1607 | |
1608 +-----------------------+
1609 | |
1610 | GP save for V.4 abi |
1611 | |
1612 +-----------------------+
1613 | |
1614 | arguments on stack |
1615 | |
1616 +-----------------------+
1617 | 4 words to save |
1618 | arguments passed |
1619 | in registers, even |
1620 low SP->| if not passed. |
b5144086 1621 memory +-----------------------+ */
6b3d1e47
SC
1622
1623HOST_WIDE_INT
b7849684 1624compute_frame_size (HOST_WIDE_INT size)
6b3d1e47
SC
1625{
1626 int regno;
b5144086
SC
1627 HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
1628 HOST_WIDE_INT var_size; /* # bytes that variables take up. */
1629 HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */
1630 HOST_WIDE_INT extra_size; /* # extra bytes. */
1631 HOST_WIDE_INT gp_reg_rounded; /* # bytes needed to store gp after rounding. */
1632 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store gp regs. */
1633 HOST_WIDE_INT fp_reg_size; /* # bytes needed to store fp regs. */
1634 long mask; /* mask of saved gp registers. */
6b3d1e47
SC
1635
1636 gp_reg_size = 0;
1637 fp_reg_size = 0;
1638 mask = 0;
1639 extra_size = IQ2000_STACK_ALIGN ((0));
1640 var_size = IQ2000_STACK_ALIGN (size);
38173d38 1641 args_size = IQ2000_STACK_ALIGN (crtl->outgoing_args_size);
6b3d1e47
SC
1642
1643 /* If a function dynamically allocates the stack and
b5144086 1644 has 0 for STACK_DYNAMIC_OFFSET then allocate some stack space. */
e3b5732b 1645 if (args_size == 0 && cfun->calls_alloca)
6b3d1e47
SC
1646 args_size = 4 * UNITS_PER_WORD;
1647
1648 total_size = var_size + args_size + extra_size;
1649
1650 /* Calculate space needed for gp registers. */
1651 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
1652 {
1653 if (MUST_SAVE_REGISTER (regno))
1654 {
1655 gp_reg_size += GET_MODE_SIZE (gpr_mode);
1656 mask |= 1L << (regno - GP_REG_FIRST);
1657 }
1658 }
1659
1660 /* We need to restore these for the handler. */
e3b5732b 1661 if (crtl->calls_eh_return)
6b3d1e47 1662 {
b5144086
SC
1663 unsigned int i;
1664
6b3d1e47
SC
1665 for (i = 0; ; ++i)
1666 {
1667 regno = EH_RETURN_DATA_REGNO (i);
b5144086 1668 if (regno == (int) INVALID_REGNUM)
6b3d1e47
SC
1669 break;
1670 gp_reg_size += GET_MODE_SIZE (gpr_mode);
1671 mask |= 1L << (regno - GP_REG_FIRST);
1672 }
1673 }
1674
6b3d1e47
SC
1675 gp_reg_rounded = IQ2000_STACK_ALIGN (gp_reg_size);
1676 total_size += gp_reg_rounded + IQ2000_STACK_ALIGN (fp_reg_size);
1677
1678 /* The gp reg is caller saved, so there is no need for leaf routines
1679 (total_size == extra_size) to save the gp reg. */
1680 if (total_size == extra_size
1681 && ! profile_flag)
1682 total_size = extra_size = 0;
1683
38173d38 1684 total_size += IQ2000_STACK_ALIGN (crtl->args.pretend_args_size);
6b3d1e47
SC
1685
1686 /* Save other computed information. */
b5144086
SC
1687 cfun->machine->total_size = total_size;
1688 cfun->machine->var_size = var_size;
1689 cfun->machine->args_size = args_size;
1690 cfun->machine->extra_size = extra_size;
1691 cfun->machine->gp_reg_size = gp_reg_size;
1692 cfun->machine->fp_reg_size = fp_reg_size;
1693 cfun->machine->mask = mask;
1694 cfun->machine->initialized = reload_completed;
1695 cfun->machine->num_gp = gp_reg_size / UNITS_PER_WORD;
6b3d1e47
SC
1696
1697 if (mask)
1698 {
1699 unsigned long offset;
1700
1701 offset = (args_size + extra_size + var_size
1702 + gp_reg_size - GET_MODE_SIZE (gpr_mode));
1703
b5144086
SC
1704 cfun->machine->gp_sp_offset = offset;
1705 cfun->machine->gp_save_offset = offset - total_size;
6b3d1e47
SC
1706 }
1707 else
1708 {
b5144086
SC
1709 cfun->machine->gp_sp_offset = 0;
1710 cfun->machine->gp_save_offset = 0;
6b3d1e47
SC
1711 }
1712
b5144086
SC
1713 cfun->machine->fp_sp_offset = 0;
1714 cfun->machine->fp_save_offset = 0;
6b3d1e47
SC
1715
1716 /* Ok, we're done. */
1717 return total_size;
1718}
1719\f
7b5cbb57
AS
1720
1721/* We can always eliminate to the frame pointer. We can eliminate to the
1722 stack pointer unless a frame pointer is needed. */
1723
1724bool
1725iq2000_can_eliminate (const int from, const int to)
1726{
1727 return (from == RETURN_ADDRESS_POINTER_REGNUM
1728 && (! leaf_function_p ()
954c7446 1729 || (to == GP_REG_FIRST + 31 && leaf_function_p ())))
7b5cbb57
AS
1730 || (from != RETURN_ADDRESS_POINTER_REGNUM
1731 && (to == HARD_FRAME_POINTER_REGNUM
1732 || (to == STACK_POINTER_REGNUM
1733 && ! frame_pointer_needed)));
1734}
1735
6b3d1e47
SC
1736/* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
1737 pointer, argument pointer, or return address pointer. TO is either
1738 the stack pointer or hard frame pointer. */
1739
1740int
b7849684 1741iq2000_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
6b3d1e47
SC
1742{
1743 int offset;
1744
1745 compute_frame_size (get_frame_size ());
1746 if ((from) == FRAME_POINTER_REGNUM)
1747 (offset) = 0;
1748 else if ((from) == ARG_POINTER_REGNUM)
b5144086 1749 (offset) = (cfun->machine->total_size);
6b3d1e47 1750 else if ((from) == RETURN_ADDRESS_POINTER_REGNUM)
b5144086
SC
1751 {
1752 if (leaf_function_p ())
1753 (offset) = 0;
1754 else (offset) = cfun->machine->gp_sp_offset
1755 + ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT))
1756 * (BYTES_BIG_ENDIAN != 0));
1757 }
954c7446
JR
1758 else
1759 gcc_unreachable ();
6b3d1e47
SC
1760
1761 return offset;
1762}
1763\f
1764/* Common code to emit the insns (or to write the instructions to a file)
1765 to save/restore registers.
1766 Other parts of the code assume that IQ2000_TEMP1_REGNUM (aka large_reg)
1767 is not modified within save_restore_insns. */
1768
1769#define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
1770
1771/* Emit instructions to load the value (SP + OFFSET) into IQ2000_TEMP2_REGNUM
1772 and return an rtl expression for the register. Write the assembly
1773 instructions directly to FILE if it is not null, otherwise emit them as
1774 rtl.
1775
1776 This function is a subroutine of save_restore_insns. It is used when
1777 OFFSET is too large to add in a single instruction. */
1778
1779static rtx
b7849684 1780iq2000_add_large_offset_to_sp (HOST_WIDE_INT offset)
6b3d1e47
SC
1781{
1782 rtx reg = gen_rtx_REG (Pmode, IQ2000_TEMP2_REGNUM);
1783 rtx offset_rtx = GEN_INT (offset);
1784
1785 emit_move_insn (reg, offset_rtx);
1786 emit_insn (gen_addsi3 (reg, reg, stack_pointer_rtx));
1787 return reg;
1788}
1789
1790/* Make INSN frame related and note that it performs the frame-related
1791 operation DWARF_PATTERN. */
1792
1793static void
6ae94a0b 1794iq2000_annotate_frame_insn (rtx_insn *insn, rtx dwarf_pattern)
6b3d1e47
SC
1795{
1796 RTX_FRAME_RELATED_P (insn) = 1;
1797 REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1798 dwarf_pattern,
1799 REG_NOTES (insn));
1800}
1801
1802/* Emit a move instruction that stores REG in MEM. Make the instruction
1803 frame related and note that it stores REG at (SP + OFFSET). */
1804
1805static void
b7849684 1806iq2000_emit_frame_related_store (rtx mem, rtx reg, HOST_WIDE_INT offset)
6b3d1e47 1807{
0a81f074 1808 rtx dwarf_address = plus_constant (Pmode, stack_pointer_rtx, offset);
6b3d1e47
SC
1809 rtx dwarf_mem = gen_rtx_MEM (GET_MODE (reg), dwarf_address);
1810
1811 iq2000_annotate_frame_insn (emit_move_insn (mem, reg),
f7df4a84 1812 gen_rtx_SET (dwarf_mem, reg));
6b3d1e47
SC
1813}
1814
b5144086
SC
1815/* Emit instructions to save/restore registers, as determined by STORE_P. */
1816
6b3d1e47 1817static void
b7849684 1818save_restore_insns (int store_p)
6b3d1e47 1819{
b5144086 1820 long mask = cfun->machine->mask;
6b3d1e47
SC
1821 int regno;
1822 rtx base_reg_rtx;
1823 HOST_WIDE_INT base_offset;
1824 HOST_WIDE_INT gp_offset;
1825 HOST_WIDE_INT end_offset;
1826
292c8018
NS
1827 gcc_assert (!frame_pointer_needed
1828 || BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST));
6b3d1e47
SC
1829
1830 if (mask == 0)
1831 {
1832 base_reg_rtx = 0, base_offset = 0;
1833 return;
1834 }
1835
1836 /* Save registers starting from high to low. The debuggers prefer at least
1837 the return register be stored at func+4, and also it allows us not to
1838 need a nop in the epilog if at least one register is reloaded in
1839 addition to return address. */
1840
1841 /* Save GP registers if needed. */
1842 /* Pick which pointer to use as a base register. For small frames, just
1843 use the stack pointer. Otherwise, use a temporary register. Save 2
1844 cycles if the save area is near the end of a large frame, by reusing
1845 the constant created in the prologue/epilogue to adjust the stack
1846 frame. */
1847
b5144086 1848 gp_offset = cfun->machine->gp_sp_offset;
6b3d1e47 1849 end_offset
b5144086 1850 = gp_offset - (cfun->machine->gp_reg_size
6b3d1e47
SC
1851 - GET_MODE_SIZE (gpr_mode));
1852
1853 if (gp_offset < 0 || end_offset < 0)
1854 internal_error
ab532386 1855 ("gp_offset (%ld) or end_offset (%ld) is less than zero",
6b3d1e47
SC
1856 (long) gp_offset, (long) end_offset);
1857
1858 else if (gp_offset < 32768)
1859 base_reg_rtx = stack_pointer_rtx, base_offset = 0;
1860 else
1861 {
1862 int regno;
1863 int reg_save_count = 0;
b5144086 1864
6b3d1e47
SC
1865 for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
1866 if (BITSET_P (mask, regno - GP_REG_FIRST)) reg_save_count += 1;
1867 base_offset = gp_offset - ((reg_save_count - 1) * 4);
1868 base_reg_rtx = iq2000_add_large_offset_to_sp (base_offset);
1869 }
1870
1871 for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
1872 {
1873 if (BITSET_P (mask, regno - GP_REG_FIRST))
1874 {
1875 rtx reg_rtx;
1876 rtx mem_rtx
f1c25d3b
KH
1877 = gen_rtx_MEM (gpr_mode,
1878 gen_rtx_PLUS (Pmode, base_reg_rtx,
6b3d1e47
SC
1879 GEN_INT (gp_offset - base_offset)));
1880
f1c25d3b 1881 reg_rtx = gen_rtx_REG (gpr_mode, regno);
6b3d1e47
SC
1882
1883 if (store_p)
1884 iq2000_emit_frame_related_store (mem_rtx, reg_rtx, gp_offset);
1885 else
1886 {
1887 emit_move_insn (reg_rtx, mem_rtx);
1888 }
1889 gp_offset -= GET_MODE_SIZE (gpr_mode);
1890 }
1891 }
1892}
1893\f
1894/* Expand the prologue into a bunch of separate insns. */
1895
1896void
b7849684 1897iq2000_expand_prologue (void)
6b3d1e47
SC
1898{
1899 int regno;
1900 HOST_WIDE_INT tsize;
1901 int last_arg_is_vararg_marker = 0;
1902 tree fndecl = current_function_decl;
1903 tree fntype = TREE_TYPE (fndecl);
1904 tree fnargs = DECL_ARGUMENTS (fndecl);
1905 rtx next_arg_reg;
1906 int i;
1907 tree next_arg;
1908 tree cur_arg;
d5cc9181
JR
1909 CUMULATIVE_ARGS args_so_far_v;
1910 cumulative_args_t args_so_far;
6b3d1e47
SC
1911 int store_args_on_stack = (iq2000_can_use_return_insn ());
1912
1913 /* If struct value address is treated as the first argument. */
b5144086 1914 if (aggregate_value_p (DECL_RESULT (fndecl), fndecl)
ad516a74 1915 && !cfun->returns_pcc_struct
b5144086 1916 && targetm.calls.struct_value_rtx (TREE_TYPE (fndecl), 1) == 0)
6b3d1e47
SC
1917 {
1918 tree type = build_pointer_type (fntype);
4c4bde29
AH
1919 tree function_result_decl = build_decl (BUILTINS_LOCATION,
1920 PARM_DECL, NULL_TREE, type);
6b3d1e47
SC
1921
1922 DECL_ARG_TYPE (function_result_decl) = type;
910ad8de 1923 DECL_CHAIN (function_result_decl) = fnargs;
6b3d1e47
SC
1924 fnargs = function_result_decl;
1925 }
1926
1927 /* For arguments passed in registers, find the register number
1928 of the first argument in the variable part of the argument list,
1929 otherwise GP_ARG_LAST+1. Note also if the last argument is
1930 the varargs special argument, and treat it as part of the
1931 variable arguments.
1932
1933 This is only needed if store_args_on_stack is true. */
d5cc9181
JR
1934 INIT_CUMULATIVE_ARGS (args_so_far_v, fntype, NULL_RTX, 0, 0);
1935 args_so_far = pack_cumulative_args (&args_so_far_v);
6b3d1e47
SC
1936 regno = GP_ARG_FIRST;
1937
1938 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
1939 {
1940 tree passed_type = DECL_ARG_TYPE (cur_arg);
ef4bddc2 1941 machine_mode passed_mode = TYPE_MODE (passed_type);
6b3d1e47
SC
1942 rtx entry_parm;
1943
1944 if (TREE_ADDRESSABLE (passed_type))
1945 {
1946 passed_type = build_pointer_type (passed_type);
1947 passed_mode = Pmode;
1948 }
1949
d5cc9181 1950 entry_parm = iq2000_function_arg (args_so_far, passed_mode,
24ef86d7 1951 passed_type, true);
6b3d1e47 1952
d5cc9181 1953 iq2000_function_arg_advance (args_so_far, passed_mode,
24ef86d7 1954 passed_type, true);
910ad8de 1955 next_arg = DECL_CHAIN (cur_arg);
6b3d1e47
SC
1956
1957 if (entry_parm && store_args_on_stack)
1958 {
1959 if (next_arg == 0
1960 && DECL_NAME (cur_arg)
1961 && ((0 == strcmp (IDENTIFIER_POINTER (DECL_NAME (cur_arg)),
1962 "__builtin_va_alist"))
1963 || (0 == strcmp (IDENTIFIER_POINTER (DECL_NAME (cur_arg)),
1964 "va_alist"))))
1965 {
1966 last_arg_is_vararg_marker = 1;
1967 break;
1968 }
1969 else
1970 {
1971 int words;
1972
292c8018 1973 gcc_assert (GET_CODE (entry_parm) == REG);
6b3d1e47 1974
5b8d96f1 1975 /* Passed in a register, so will get homed automatically. */
6b3d1e47
SC
1976 if (GET_MODE (entry_parm) == BLKmode)
1977 words = (int_size_in_bytes (passed_type) + 3) / 4;
1978 else
1979 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
1980
1981 regno = REGNO (entry_parm) + words - 1;
1982 }
1983 }
1984 else
1985 {
1986 regno = GP_ARG_LAST+1;
1987 break;
1988 }
1989 }
1990
1991 /* In order to pass small structures by value in registers we need to
1992 shift the value into the high part of the register.
24ef86d7
NF
1993 iq2000_unction_arg has encoded a PARALLEL rtx, holding a vector of
1994 adjustments to be made as the next_arg_reg variable, so we split up
1995 the insns, and emit them separately. */
d5cc9181 1996 next_arg_reg = iq2000_function_arg (args_so_far, VOIDmode,
24ef86d7 1997 void_type_node, true);
6b3d1e47
SC
1998 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
1999 {
2000 rtvec adjust = XVEC (next_arg_reg, 0);
2001 int num = GET_NUM_ELEM (adjust);
2002
2003 for (i = 0; i < num; i++)
2004 {
954c7446 2005 rtx pattern;
6b3d1e47
SC
2006
2007 pattern = RTVEC_ELT (adjust, i);
2008 if (GET_CODE (pattern) != SET
2009 || GET_CODE (SET_SRC (pattern)) != ASHIFT)
2010 abort_with_insn (pattern, "Insn is not a shift");
2011 PUT_CODE (SET_SRC (pattern), ASHIFTRT);
2012
954c7446 2013 emit_insn (pattern);
6b3d1e47
SC
2014 }
2015 }
2016
2017 tsize = compute_frame_size (get_frame_size ());
2018
2019 /* If this function is a varargs function, store any registers that
2020 would normally hold arguments ($4 - $7) on the stack. */
2021 if (store_args_on_stack
f38958e8 2022 && (stdarg_p (fntype)
6b3d1e47
SC
2023 || last_arg_is_vararg_marker))
2024 {
2025 int offset = (regno - GP_ARG_FIRST) * UNITS_PER_WORD;
2026 rtx ptr = stack_pointer_rtx;
2027
2028 for (; regno <= GP_ARG_LAST; regno++)
2029 {
2030 if (offset != 0)
f1c25d3b
KH
2031 ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
2032 emit_move_insn (gen_rtx_MEM (gpr_mode, ptr),
2033 gen_rtx_REG (gpr_mode, regno));
6b3d1e47
SC
2034
2035 offset += GET_MODE_SIZE (gpr_mode);
2036 }
2037 }
2038
2039 if (tsize > 0)
2040 {
2041 rtx tsize_rtx = GEN_INT (tsize);
6ae94a0b
DM
2042 rtx adjustment_rtx, dwarf_pattern;
2043 rtx_insn *insn;
6b3d1e47
SC
2044
2045 if (tsize > 32767)
2046 {
f1c25d3b 2047 adjustment_rtx = gen_rtx_REG (Pmode, IQ2000_TEMP1_REGNUM);
6b3d1e47
SC
2048 emit_move_insn (adjustment_rtx, tsize_rtx);
2049 }
2050 else
2051 adjustment_rtx = tsize_rtx;
2052
2053 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
2054 adjustment_rtx));
2055
f7df4a84 2056 dwarf_pattern = gen_rtx_SET (stack_pointer_rtx,
0a81f074
RS
2057 plus_constant (Pmode, stack_pointer_rtx,
2058 -tsize));
6b3d1e47
SC
2059
2060 iq2000_annotate_frame_insn (insn, dwarf_pattern);
2061
2062 save_restore_insns (1);
2063
2064 if (frame_pointer_needed)
2065 {
6ae94a0b 2066 rtx_insn *insn = 0;
6b3d1e47
SC
2067
2068 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
2069 stack_pointer_rtx));
2070
2071 if (insn)
2072 RTX_FRAME_RELATED_P (insn) = 1;
2073 }
2074 }
2075
ed1332ee
NC
2076 if (flag_stack_usage_info)
2077 current_function_static_stack_size = cfun->machine->total_size;
2078
6b3d1e47
SC
2079 emit_insn (gen_blockage ());
2080}
2081\f
2082/* Expand the epilogue into a bunch of separate insns. */
2083
2084void
b7849684 2085iq2000_expand_epilogue (void)
6b3d1e47 2086{
b5144086 2087 HOST_WIDE_INT tsize = cfun->machine->total_size;
6b3d1e47
SC
2088 rtx tsize_rtx = GEN_INT (tsize);
2089 rtx tmp_rtx = (rtx)0;
2090
2091 if (iq2000_can_use_return_insn ())
2092 {
9054261d 2093 emit_jump_insn (gen_return ());
6b3d1e47
SC
2094 return;
2095 }
2096
2097 if (tsize > 32767)
2098 {
2099 tmp_rtx = gen_rtx_REG (Pmode, IQ2000_TEMP1_REGNUM);
2100 emit_move_insn (tmp_rtx, tsize_rtx);
2101 tsize_rtx = tmp_rtx;
2102 }
2103
2104 if (tsize > 0)
2105 {
2106 if (frame_pointer_needed)
2107 {
2108 emit_insn (gen_blockage ());
2109
2110 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
2111 }
2112
2113 save_restore_insns (0);
2114
e3b5732b 2115 if (crtl->calls_eh_return)
6b3d1e47
SC
2116 {
2117 rtx eh_ofs = EH_RETURN_STACKADJ_RTX;
2118 emit_insn (gen_addsi3 (eh_ofs, eh_ofs, tsize_rtx));
2119 tsize_rtx = eh_ofs;
2120 }
2121
2122 emit_insn (gen_blockage ());
2123
e3b5732b 2124 if (tsize != 0 || crtl->calls_eh_return)
6b3d1e47
SC
2125 {
2126 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
2127 tsize_rtx));
2128 }
2129 }
2130
e3b5732b 2131 if (crtl->calls_eh_return)
6b3d1e47
SC
2132 {
2133 /* Perform the additional bump for __throw. */
f1c25d3b 2134 emit_move_insn (gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM),
6b3d1e47 2135 stack_pointer_rtx);
c41c1387 2136 emit_use (gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM));
6b3d1e47
SC
2137 emit_jump_insn (gen_eh_return_internal ());
2138 }
2139 else
f1c25d3b 2140 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
6b3d1e47
SC
2141 GP_REG_FIRST + 31)));
2142}
2143
2144void
b7849684 2145iq2000_expand_eh_return (rtx address)
6b3d1e47 2146{
b5144086 2147 HOST_WIDE_INT gp_offset = cfun->machine->gp_sp_offset;
6b3d1e47
SC
2148 rtx scratch;
2149
0a81f074 2150 scratch = plus_constant (Pmode, stack_pointer_rtx, gp_offset);
6b3d1e47
SC
2151 emit_move_insn (gen_rtx_MEM (GET_MODE (address), scratch), address);
2152}
2153\f
2154/* Return nonzero if this function is known to have a null epilogue.
2155 This allows the optimizer to omit jumps to jumps if no stack
2156 was created. */
2157
2158int
b7849684 2159iq2000_can_use_return_insn (void)
6b3d1e47
SC
2160{
2161 if (! reload_completed)
2162 return 0;
2163
6fb5fa3c 2164 if (df_regs_ever_live_p (31) || profile_flag)
6b3d1e47
SC
2165 return 0;
2166
b5144086
SC
2167 if (cfun->machine->initialized)
2168 return cfun->machine->total_size == 0;
6b3d1e47
SC
2169
2170 return compute_frame_size (get_frame_size ()) == 0;
2171}
2172\f
6b3d1e47
SC
2173/* Choose the section to use for the constant rtx expression X that has
2174 mode MODE. */
2175
d6b5193b 2176static section *
ef4bddc2 2177iq2000_select_rtx_section (machine_mode mode, rtx x ATTRIBUTE_UNUSED,
b7849684 2178 unsigned HOST_WIDE_INT align)
6b3d1e47
SC
2179{
2180 /* For embedded applications, always put constants in read-only data,
2181 in order to reduce RAM usage. */
d6b5193b 2182 return mergeable_constant_section (mode, align, 0);
6b3d1e47
SC
2183}
2184
2185/* Choose the section to use for DECL. RELOC is true if its value contains
2186 any relocatable expression.
2187
2188 Some of the logic used here needs to be replicated in
2189 ENCODE_SECTION_INFO in iq2000.h so that references to these symbols
2190 are done correctly. */
2191
d6b5193b 2192static section *
b7849684
JE
2193iq2000_select_section (tree decl, int reloc ATTRIBUTE_UNUSED,
2194 unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
6b3d1e47
SC
2195{
2196 if (TARGET_EMBEDDED_DATA)
2197 {
2198 /* For embedded applications, always put an object in read-only data
2199 if possible, in order to reduce RAM usage. */
3521b33c
ZW
2200 if ((TREE_CODE (decl) == VAR_DECL
2201 && TREE_READONLY (decl) && !TREE_SIDE_EFFECTS (decl)
2202 && DECL_INITIAL (decl)
2203 && (DECL_INITIAL (decl) == error_mark_node
2204 || TREE_CONSTANT (DECL_INITIAL (decl))))
2205 /* Deal with calls from output_constant_def_contents. */
2206 || TREE_CODE (decl) != VAR_DECL)
d6b5193b 2207 return readonly_data_section;
6b3d1e47 2208 else
d6b5193b 2209 return data_section;
6b3d1e47
SC
2210 }
2211 else
2212 {
2213 /* For hosted applications, always put an object in small data if
2214 possible, as this gives the best performance. */
3521b33c
ZW
2215 if ((TREE_CODE (decl) == VAR_DECL
2216 && TREE_READONLY (decl) && !TREE_SIDE_EFFECTS (decl)
2217 && DECL_INITIAL (decl)
2218 && (DECL_INITIAL (decl) == error_mark_node
2219 || TREE_CONSTANT (DECL_INITIAL (decl))))
2220 /* Deal with calls from output_constant_def_contents. */
2221 || TREE_CODE (decl) != VAR_DECL)
d6b5193b 2222 return readonly_data_section;
6b3d1e47 2223 else
d6b5193b 2224 return data_section;
6b3d1e47
SC
2225 }
2226}
2227/* Return register to use for a function return value with VALTYPE for function
2228 FUNC. */
2229
7ae62237
AS
2230static rtx
2231iq2000_function_value (const_tree valtype,
2232 const_tree fn_decl_or_type,
2233 bool outgoing ATTRIBUTE_UNUSED)
6b3d1e47
SC
2234{
2235 int reg = GP_RETURN;
ef4bddc2 2236 machine_mode mode = TYPE_MODE (valtype);
8df83eae 2237 int unsignedp = TYPE_UNSIGNED (valtype);
954c7446 2238 const_tree func = fn_decl_or_type;
7ae62237
AS
2239
2240 if (fn_decl_or_type
2241 && !DECL_P (fn_decl_or_type))
2242 fn_decl_or_type = NULL;
6b3d1e47 2243
cde0f3fd
PB
2244 /* Since we promote return types, we must promote the mode here too. */
2245 mode = promote_function_mode (valtype, mode, &unsignedp, func, 1);
6b3d1e47
SC
2246
2247 return gen_rtx_REG (mode, reg);
2248}
7ae62237
AS
2249
2250/* Worker function for TARGET_LIBCALL_VALUE. */
2251
2252static rtx
ef4bddc2 2253iq2000_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
7ae62237
AS
2254{
2255 return gen_rtx_REG (((GET_MODE_CLASS (mode) != MODE_INT
2256 || GET_MODE_SIZE (mode) >= 4)
2257 ? mode : SImode),
2258 GP_RETURN);
2259}
2260
2261/* Worker function for FUNCTION_VALUE_REGNO_P.
2262
2263 On the IQ2000, R2 and R3 are the only register thus used. */
2264
2265bool
2266iq2000_function_value_regno_p (const unsigned int regno)
2267{
2268 return (regno == GP_RETURN);
2269}
2270
6b3d1e47 2271\f
8cd5a4e0 2272/* Return true when an argument must be passed by reference. */
6b3d1e47 2273
8cd5a4e0 2274static bool
ef4bddc2 2275iq2000_pass_by_reference (cumulative_args_t cum_v, machine_mode mode,
586de218 2276 const_tree type, bool named ATTRIBUTE_UNUSED)
6b3d1e47 2277{
d5cc9181 2278 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
6b3d1e47
SC
2279 int size;
2280
2281 /* We must pass by reference if we would be both passing in registers
2282 and the stack. This is because any subsequent partial arg would be
2283 handled incorrectly in this case. */
fe984136 2284 if (cum && targetm.calls.must_pass_in_stack (mode, type))
6b3d1e47
SC
2285 {
2286 /* Don't pass the actual CUM to FUNCTION_ARG, because we would
2287 get double copies of any offsets generated for small structs
2288 passed in registers. */
2289 CUMULATIVE_ARGS temp;
b5144086 2290
6b3d1e47 2291 temp = *cum;
d5cc9181
JR
2292 if (iq2000_function_arg (pack_cumulative_args (&temp), mode, type, named)
2293 != 0)
6b3d1e47
SC
2294 return 1;
2295 }
2296
2297 if (type == NULL_TREE || mode == DImode || mode == DFmode)
2298 return 0;
2299
2300 size = int_size_in_bytes (type);
2301 return size == -1 || size > UNITS_PER_WORD;
2302}
2303
2304/* Return the length of INSN. LENGTH is the initial length computed by
2305 attributes in the machine-description file. */
2306
2307int
6ae94a0b 2308iq2000_adjust_insn_length (rtx_insn *insn, int length)
6b3d1e47
SC
2309{
2310 /* A unconditional jump has an unfilled delay slot if it is not part
b5144086 2311 of a sequence. A conditional jump normally has a delay slot. */
6b3d1e47 2312 if (simplejump_p (insn)
b64925dc
SB
2313 || ( (JUMP_P (insn)
2314 || CALL_P (insn))))
6b3d1e47
SC
2315 length += 4;
2316
2317 return length;
2318}
2319
2320/* Output assembly instructions to perform a conditional branch.
2321
2322 INSN is the branch instruction. OPERANDS[0] is the condition.
2323 OPERANDS[1] is the target of the branch. OPERANDS[2] is the target
2324 of the first operand to the condition. If TWO_OPERANDS_P is
4375e090 2325 nonzero the comparison takes two operands; OPERANDS[3] will be the
6b3d1e47
SC
2326 second operand.
2327
4375e090
KH
2328 If INVERTED_P is nonzero we are to branch if the condition does
2329 not hold. If FLOAT_P is nonzero this is a floating-point comparison.
6b3d1e47
SC
2330
2331 LENGTH is the length (in bytes) of the sequence we are to generate.
2332 That tells us whether to generate a simple conditional branch, or a
2333 reversed conditional branch around a `jr' instruction. */
2334
2335char *
6ae94a0b
DM
2336iq2000_output_conditional_branch (rtx_insn *insn, rtx * operands,
2337 int two_operands_p, int float_p,
2338 int inverted_p, int length)
6b3d1e47
SC
2339{
2340 static char buffer[200];
2341 /* The kind of comparison we are doing. */
2342 enum rtx_code code = GET_CODE (operands[0]);
5b8d96f1 2343 /* Nonzero if the opcode for the comparison needs a `z' indicating
2cac216b 2344 that it is a comparison against zero. */
6b3d1e47
SC
2345 int need_z_p;
2346 /* A string to use in the assembly output to represent the first
2347 operand. */
2348 const char *op1 = "%z2";
2349 /* A string to use in the assembly output to represent the second
2350 operand. Use the hard-wired zero register if there's no second
2351 operand. */
2352 const char *op2 = (two_operands_p ? ",%z3" : ",%.");
2353 /* The operand-printing string for the comparison. */
2354 const char *comp = (float_p ? "%F0" : "%C0");
2355 /* The operand-printing string for the inverted comparison. */
2356 const char *inverted_comp = (float_p ? "%W0" : "%N0");
2357
b5144086 2358 /* Likely variants of each branch instruction annul the instruction
6b3d1e47
SC
2359 in the delay slot if the branch is not taken. */
2360 iq2000_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
2361
2362 if (!two_operands_p)
2363 {
2364 /* To compute whether than A > B, for example, we normally
2365 subtract B from A and then look at the sign bit. But, if we
2366 are doing an unsigned comparison, and B is zero, we don't
2367 have to do the subtraction. Instead, we can just check to
4375e090 2368 see if A is nonzero. Thus, we change the CODE here to
6b3d1e47
SC
2369 reflect the simpler comparison operation. */
2370 switch (code)
2371 {
2372 case GTU:
2373 code = NE;
2374 break;
2375
2376 case LEU:
2377 code = EQ;
2378 break;
2379
2380 case GEU:
2381 /* A condition which will always be true. */
2382 code = EQ;
2383 op1 = "%.";
2384 break;
2385
2386 case LTU:
2387 /* A condition which will always be false. */
2388 code = NE;
2389 op1 = "%.";
2390 break;
2391
2392 default:
2393 /* Not a special case. */
2394 break;
2395 }
2396 }
2397
2398 /* Relative comparisons are always done against zero. But
2399 equality comparisons are done between two operands, and therefore
2400 do not require a `z' in the assembly language output. */
2401 need_z_p = (!float_p && code != EQ && code != NE);
2402 /* For comparisons against zero, the zero is not provided
2403 explicitly. */
2404 if (need_z_p)
2405 op2 = "";
2406
2407 /* Begin by terminating the buffer. That way we can always use
2408 strcat to add to it. */
2409 buffer[0] = '\0';
2410
2411 switch (length)
2412 {
2413 case 4:
2414 case 8:
2415 /* Just a simple conditional branch. */
2416 if (float_p)
2417 sprintf (buffer, "b%s%%?\t%%Z2%%1",
2418 inverted_p ? inverted_comp : comp);
2419 else
2420 sprintf (buffer, "b%s%s%%?\t%s%s,%%1",
2421 inverted_p ? inverted_comp : comp,
2422 need_z_p ? "z" : "",
2423 op1,
2424 op2);
2425 return buffer;
2426
2427 case 12:
2428 case 16:
2429 {
2430 /* Generate a reversed conditional branch around ` j'
2431 instruction:
2432
2433 .set noreorder
2434 .set nomacro
2435 bc l
2436 nop
2437 j target
2438 .set macro
2439 .set reorder
2440 l:
2441
2442 Because we have to jump four bytes *past* the following
2443 instruction if this branch was annulled, we can't just use
2444 a label, as in the picture above; there's no way to put the
2445 label after the next instruction, as the assembler does not
2446 accept `.L+4' as the target of a branch. (We can't just
2447 wait until the next instruction is output; it might be a
2448 macro and take up more than four bytes. Once again, we see
2449 why we want to eliminate macros.)
2450
2451 If the branch is annulled, we jump four more bytes that we
2452 would otherwise; that way we skip the annulled instruction
2453 in the delay slot. */
2454
2455 const char *target
2456 = ((iq2000_branch_likely || length == 16) ? ".+16" : ".+12");
2457 char *c;
2458
2459 c = strchr (buffer, '\0');
59b9a953 2460 /* Generate the reversed comparison. This takes four
6b3d1e47
SC
2461 bytes. */
2462 if (float_p)
2463 sprintf (c, "b%s\t%%Z2%s",
2464 inverted_p ? comp : inverted_comp,
2465 target);
2466 else
2467 sprintf (c, "b%s%s\t%s%s,%s",
2468 inverted_p ? comp : inverted_comp,
2469 need_z_p ? "z" : "",
2470 op1,
2471 op2,
2472 target);
2473 strcat (c, "\n\tnop\n\tj\t%1");
2474 if (length == 16)
2475 /* The delay slot was unfilled. Since we're inside
2476 .noreorder, the assembler will not fill in the NOP for
2477 us, so we must do it ourselves. */
2478 strcat (buffer, "\n\tnop");
2479 return buffer;
2480 }
2481
2482 default:
292c8018 2483 gcc_unreachable ();
6b3d1e47
SC
2484 }
2485
2486 /* NOTREACHED */
2487 return 0;
2488}
2489
6e34d3a3 2490#define def_builtin(NAME, TYPE, CODE) \
c79efc4d
RÁE
2491 add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
2492 NULL, NULL_TREE)
6b3d1e47 2493
b5144086 2494static void
b7849684 2495iq2000_init_builtins (void)
6b3d1e47 2496{
6b3d1e47
SC
2497 tree void_ftype, void_ftype_int, void_ftype_int_int;
2498 tree void_ftype_int_int_int;
2499 tree int_ftype_int, int_ftype_int_int, int_ftype_int_int_int;
2500 tree int_ftype_int_int_int_int;
2501
2502 /* func () */
2503 void_ftype
baeec5f2 2504 = build_function_type_list (void_type_node, NULL_TREE);
6b3d1e47
SC
2505
2506 /* func (int) */
2507 void_ftype_int
baeec5f2 2508 = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
6b3d1e47
SC
2509
2510 /* void func (int, int) */
2511 void_ftype_int_int
baeec5f2
NF
2512 = build_function_type_list (void_type_node,
2513 integer_type_node,
2514 integer_type_node,
2515 NULL_TREE);
6b3d1e47
SC
2516
2517 /* int func (int) */
2518 int_ftype_int
baeec5f2
NF
2519 = build_function_type_list (integer_type_node,
2520 integer_type_node, NULL_TREE);
6b3d1e47
SC
2521
2522 /* int func (int, int) */
2523 int_ftype_int_int
baeec5f2
NF
2524 = build_function_type_list (integer_type_node,
2525 integer_type_node,
2526 integer_type_node,
2527 NULL_TREE);
6b3d1e47
SC
2528
2529 /* void func (int, int, int) */
baeec5f2
NF
2530 void_ftype_int_int_int
2531 = build_function_type_list (void_type_node,
2532 integer_type_node,
2533 integer_type_node,
2534 integer_type_node,
2535 NULL_TREE);
6b3d1e47
SC
2536
2537 /* int func (int, int, int) */
2538 int_ftype_int_int_int
baeec5f2
NF
2539 = build_function_type_list (integer_type_node,
2540 integer_type_node,
2541 integer_type_node,
2542 integer_type_node,
2543 NULL_TREE);
6b3d1e47
SC
2544
2545 /* int func (int, int, int, int) */
2546 int_ftype_int_int_int_int
baeec5f2
NF
2547 = build_function_type_list (integer_type_node,
2548 integer_type_node,
2549 integer_type_node,
2550 integer_type_node,
2551 integer_type_node,
2552 NULL_TREE);
6b3d1e47
SC
2553
2554 def_builtin ("__builtin_ado16", int_ftype_int_int, IQ2000_BUILTIN_ADO16);
2555 def_builtin ("__builtin_ram", int_ftype_int_int_int_int, IQ2000_BUILTIN_RAM);
2556 def_builtin ("__builtin_chkhdr", void_ftype_int_int, IQ2000_BUILTIN_CHKHDR);
2557 def_builtin ("__builtin_pkrl", void_ftype_int_int, IQ2000_BUILTIN_PKRL);
2558 def_builtin ("__builtin_cfc0", int_ftype_int, IQ2000_BUILTIN_CFC0);
2559 def_builtin ("__builtin_cfc1", int_ftype_int, IQ2000_BUILTIN_CFC1);
2560 def_builtin ("__builtin_cfc2", int_ftype_int, IQ2000_BUILTIN_CFC2);
2561 def_builtin ("__builtin_cfc3", int_ftype_int, IQ2000_BUILTIN_CFC3);
2562 def_builtin ("__builtin_ctc0", void_ftype_int_int, IQ2000_BUILTIN_CTC0);
2563 def_builtin ("__builtin_ctc1", void_ftype_int_int, IQ2000_BUILTIN_CTC1);
2564 def_builtin ("__builtin_ctc2", void_ftype_int_int, IQ2000_BUILTIN_CTC2);
2565 def_builtin ("__builtin_ctc3", void_ftype_int_int, IQ2000_BUILTIN_CTC3);
2566 def_builtin ("__builtin_mfc0", int_ftype_int, IQ2000_BUILTIN_MFC0);
2567 def_builtin ("__builtin_mfc1", int_ftype_int, IQ2000_BUILTIN_MFC1);
2568 def_builtin ("__builtin_mfc2", int_ftype_int, IQ2000_BUILTIN_MFC2);
2569 def_builtin ("__builtin_mfc3", int_ftype_int, IQ2000_BUILTIN_MFC3);
2570 def_builtin ("__builtin_mtc0", void_ftype_int_int, IQ2000_BUILTIN_MTC0);
2571 def_builtin ("__builtin_mtc1", void_ftype_int_int, IQ2000_BUILTIN_MTC1);
2572 def_builtin ("__builtin_mtc2", void_ftype_int_int, IQ2000_BUILTIN_MTC2);
2573 def_builtin ("__builtin_mtc3", void_ftype_int_int, IQ2000_BUILTIN_MTC3);
2574 def_builtin ("__builtin_lur", void_ftype_int_int, IQ2000_BUILTIN_LUR);
2575 def_builtin ("__builtin_rb", void_ftype_int_int, IQ2000_BUILTIN_RB);
2576 def_builtin ("__builtin_rx", void_ftype_int_int, IQ2000_BUILTIN_RX);
2577 def_builtin ("__builtin_srrd", void_ftype_int, IQ2000_BUILTIN_SRRD);
2578 def_builtin ("__builtin_srwr", void_ftype_int_int, IQ2000_BUILTIN_SRWR);
2579 def_builtin ("__builtin_wb", void_ftype_int_int, IQ2000_BUILTIN_WB);
2580 def_builtin ("__builtin_wx", void_ftype_int_int, IQ2000_BUILTIN_WX);
2581 def_builtin ("__builtin_luc32l", void_ftype_int_int, IQ2000_BUILTIN_LUC32L);
2582 def_builtin ("__builtin_luc64", void_ftype_int_int, IQ2000_BUILTIN_LUC64);
2583 def_builtin ("__builtin_luc64l", void_ftype_int_int, IQ2000_BUILTIN_LUC64L);
2584 def_builtin ("__builtin_luk", void_ftype_int_int, IQ2000_BUILTIN_LUK);
2585 def_builtin ("__builtin_lulck", void_ftype_int, IQ2000_BUILTIN_LULCK);
2586 def_builtin ("__builtin_lum32", void_ftype_int_int, IQ2000_BUILTIN_LUM32);
2587 def_builtin ("__builtin_lum32l", void_ftype_int_int, IQ2000_BUILTIN_LUM32L);
2588 def_builtin ("__builtin_lum64", void_ftype_int_int, IQ2000_BUILTIN_LUM64);
2589 def_builtin ("__builtin_lum64l", void_ftype_int_int, IQ2000_BUILTIN_LUM64L);
2590 def_builtin ("__builtin_lurl", void_ftype_int_int, IQ2000_BUILTIN_LURL);
2591 def_builtin ("__builtin_mrgb", int_ftype_int_int_int, IQ2000_BUILTIN_MRGB);
2592 def_builtin ("__builtin_srrdl", void_ftype_int, IQ2000_BUILTIN_SRRDL);
2593 def_builtin ("__builtin_srulck", void_ftype_int, IQ2000_BUILTIN_SRULCK);
2594 def_builtin ("__builtin_srwru", void_ftype_int_int, IQ2000_BUILTIN_SRWRU);
2595 def_builtin ("__builtin_trapqfl", void_ftype, IQ2000_BUILTIN_TRAPQFL);
2596 def_builtin ("__builtin_trapqne", void_ftype, IQ2000_BUILTIN_TRAPQNE);
2597 def_builtin ("__builtin_traprel", void_ftype_int, IQ2000_BUILTIN_TRAPREL);
2598 def_builtin ("__builtin_wbu", void_ftype_int_int_int, IQ2000_BUILTIN_WBU);
2599 def_builtin ("__builtin_syscall", void_ftype, IQ2000_BUILTIN_SYSCALL);
2600}
2601
5039610b 2602/* Builtin for ICODE having ARGCOUNT args in EXP where each arg
b5144086 2603 has an rtx CODE. */
6b3d1e47
SC
2604
2605static rtx
5039610b 2606expand_one_builtin (enum insn_code icode, rtx target, tree exp,
b7849684 2607 enum rtx_code *code, int argcount)
6b3d1e47
SC
2608{
2609 rtx pat;
2610 tree arg [5];
2611 rtx op [5];
ef4bddc2 2612 machine_mode mode [5];
6b3d1e47
SC
2613 int i;
2614
2615 mode[0] = insn_data[icode].operand[0].mode;
2616 for (i = 0; i < argcount; i++)
2617 {
5039610b 2618 arg[i] = CALL_EXPR_ARG (exp, i);
954c7446 2619 op[i] = expand_normal (arg[i]);
6b3d1e47
SC
2620 mode[i] = insn_data[icode].operand[i].mode;
2621 if (code[i] == CONST_INT && GET_CODE (op[i]) != CONST_INT)
9e637a26 2622 error ("argument %qd is not a constant", i + 1);
6b3d1e47
SC
2623 if (code[i] == REG
2624 && ! (*insn_data[icode].operand[i].predicate) (op[i], mode[i]))
2625 op[i] = copy_to_mode_reg (mode[i], op[i]);
2626 }
2627
2628 if (insn_data[icode].operand[0].constraint[0] == '=')
2629 {
2630 if (target == 0
2631 || GET_MODE (target) != mode[0]
2632 || ! (*insn_data[icode].operand[0].predicate) (target, mode[0]))
2633 target = gen_reg_rtx (mode[0]);
2634 }
2635 else
2636 target = 0;
2637
2638 switch (argcount)
2639 {
2640 case 0:
2641 pat = GEN_FCN (icode) (target);
2642 case 1:
2643 if (target)
2644 pat = GEN_FCN (icode) (target, op[0]);
2645 else
2646 pat = GEN_FCN (icode) (op[0]);
2647 break;
2648 case 2:
2649 if (target)
2650 pat = GEN_FCN (icode) (target, op[0], op[1]);
2651 else
2652 pat = GEN_FCN (icode) (op[0], op[1]);
2653 break;
2654 case 3:
2655 if (target)
2656 pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
2657 else
2658 pat = GEN_FCN (icode) (op[0], op[1], op[2]);
2659 break;
2660 case 4:
2661 if (target)
2662 pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
2663 else
2664 pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
2665 break;
2666 default:
292c8018 2667 gcc_unreachable ();
6b3d1e47
SC
2668 }
2669
2670 if (! pat)
2671 return 0;
2672 emit_insn (pat);
2673 return target;
2674}
2675
2676/* Expand an expression EXP that calls a built-in function,
2677 with result going to TARGET if that's convenient
2678 (and in mode MODE if that's convenient).
2679 SUBTARGET may be used as the target for computing one of EXP's operands.
2680 IGNORE is nonzero if the value is to be ignored. */
2681
b5144086 2682static rtx
b7849684 2683iq2000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
ef4bddc2 2684 machine_mode mode ATTRIBUTE_UNUSED,
b7849684 2685 int ignore ATTRIBUTE_UNUSED)
6b3d1e47 2686{
5039610b 2687 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
6b3d1e47
SC
2688 int fcode = DECL_FUNCTION_CODE (fndecl);
2689 enum rtx_code code [5];
2690
2691 code[0] = REG;
2692 code[1] = REG;
2693 code[2] = REG;
2694 code[3] = REG;
2695 code[4] = REG;
2696 switch (fcode)
2697 {
2698 default:
2699 break;
2700
2701 case IQ2000_BUILTIN_ADO16:
5039610b 2702 return expand_one_builtin (CODE_FOR_ado16, target, exp, code, 2);
6b3d1e47
SC
2703
2704 case IQ2000_BUILTIN_RAM:
2705 code[1] = CONST_INT;
2706 code[2] = CONST_INT;
2707 code[3] = CONST_INT;
5039610b 2708 return expand_one_builtin (CODE_FOR_ram, target, exp, code, 4);
6b3d1e47
SC
2709
2710 case IQ2000_BUILTIN_CHKHDR:
5039610b 2711 return expand_one_builtin (CODE_FOR_chkhdr, target, exp, code, 2);
6b3d1e47
SC
2712
2713 case IQ2000_BUILTIN_PKRL:
5039610b 2714 return expand_one_builtin (CODE_FOR_pkrl, target, exp, code, 2);
6b3d1e47
SC
2715
2716 case IQ2000_BUILTIN_CFC0:
2717 code[0] = CONST_INT;
5039610b 2718 return expand_one_builtin (CODE_FOR_cfc0, target, exp, code, 1);
6b3d1e47
SC
2719
2720 case IQ2000_BUILTIN_CFC1:
2721 code[0] = CONST_INT;
5039610b 2722 return expand_one_builtin (CODE_FOR_cfc1, target, exp, code, 1);
6b3d1e47
SC
2723
2724 case IQ2000_BUILTIN_CFC2:
2725 code[0] = CONST_INT;
5039610b 2726 return expand_one_builtin (CODE_FOR_cfc2, target, exp, code, 1);
6b3d1e47
SC
2727
2728 case IQ2000_BUILTIN_CFC3:
2729 code[0] = CONST_INT;
5039610b 2730 return expand_one_builtin (CODE_FOR_cfc3, target, exp, code, 1);
6b3d1e47
SC
2731
2732 case IQ2000_BUILTIN_CTC0:
2733 code[1] = CONST_INT;
5039610b 2734 return expand_one_builtin (CODE_FOR_ctc0, target, exp, code, 2);
6b3d1e47
SC
2735
2736 case IQ2000_BUILTIN_CTC1:
2737 code[1] = CONST_INT;
5039610b 2738 return expand_one_builtin (CODE_FOR_ctc1, target, exp, code, 2);
6b3d1e47
SC
2739
2740 case IQ2000_BUILTIN_CTC2:
2741 code[1] = CONST_INT;
5039610b 2742 return expand_one_builtin (CODE_FOR_ctc2, target, exp, code, 2);
6b3d1e47
SC
2743
2744 case IQ2000_BUILTIN_CTC3:
2745 code[1] = CONST_INT;
5039610b 2746 return expand_one_builtin (CODE_FOR_ctc3, target, exp, code, 2);
6b3d1e47
SC
2747
2748 case IQ2000_BUILTIN_MFC0:
2749 code[0] = CONST_INT;
5039610b 2750 return expand_one_builtin (CODE_FOR_mfc0, target, exp, code, 1);
6b3d1e47
SC
2751
2752 case IQ2000_BUILTIN_MFC1:
2753 code[0] = CONST_INT;
5039610b 2754 return expand_one_builtin (CODE_FOR_mfc1, target, exp, code, 1);
6b3d1e47
SC
2755
2756 case IQ2000_BUILTIN_MFC2:
2757 code[0] = CONST_INT;
5039610b 2758 return expand_one_builtin (CODE_FOR_mfc2, target, exp, code, 1);
6b3d1e47
SC
2759
2760 case IQ2000_BUILTIN_MFC3:
2761 code[0] = CONST_INT;
5039610b 2762 return expand_one_builtin (CODE_FOR_mfc3, target, exp, code, 1);
6b3d1e47
SC
2763
2764 case IQ2000_BUILTIN_MTC0:
2765 code[1] = CONST_INT;
5039610b 2766 return expand_one_builtin (CODE_FOR_mtc0, target, exp, code, 2);
6b3d1e47
SC
2767
2768 case IQ2000_BUILTIN_MTC1:
2769 code[1] = CONST_INT;
5039610b 2770 return expand_one_builtin (CODE_FOR_mtc1, target, exp, code, 2);
6b3d1e47
SC
2771
2772 case IQ2000_BUILTIN_MTC2:
2773 code[1] = CONST_INT;
5039610b 2774 return expand_one_builtin (CODE_FOR_mtc2, target, exp, code, 2);
6b3d1e47
SC
2775
2776 case IQ2000_BUILTIN_MTC3:
2777 code[1] = CONST_INT;
5039610b 2778 return expand_one_builtin (CODE_FOR_mtc3, target, exp, code, 2);
6b3d1e47
SC
2779
2780 case IQ2000_BUILTIN_LUR:
5039610b 2781 return expand_one_builtin (CODE_FOR_lur, target, exp, code, 2);
6b3d1e47
SC
2782
2783 case IQ2000_BUILTIN_RB:
5039610b 2784 return expand_one_builtin (CODE_FOR_rb, target, exp, code, 2);
6b3d1e47
SC
2785
2786 case IQ2000_BUILTIN_RX:
5039610b 2787 return expand_one_builtin (CODE_FOR_rx, target, exp, code, 2);
6b3d1e47
SC
2788
2789 case IQ2000_BUILTIN_SRRD:
5039610b 2790 return expand_one_builtin (CODE_FOR_srrd, target, exp, code, 1);
6b3d1e47
SC
2791
2792 case IQ2000_BUILTIN_SRWR:
5039610b 2793 return expand_one_builtin (CODE_FOR_srwr, target, exp, code, 2);
6b3d1e47
SC
2794
2795 case IQ2000_BUILTIN_WB:
5039610b 2796 return expand_one_builtin (CODE_FOR_wb, target, exp, code, 2);
6b3d1e47
SC
2797
2798 case IQ2000_BUILTIN_WX:
5039610b 2799 return expand_one_builtin (CODE_FOR_wx, target, exp, code, 2);
6b3d1e47
SC
2800
2801 case IQ2000_BUILTIN_LUC32L:
5039610b 2802 return expand_one_builtin (CODE_FOR_luc32l, target, exp, code, 2);
6b3d1e47
SC
2803
2804 case IQ2000_BUILTIN_LUC64:
5039610b 2805 return expand_one_builtin (CODE_FOR_luc64, target, exp, code, 2);
6b3d1e47
SC
2806
2807 case IQ2000_BUILTIN_LUC64L:
5039610b 2808 return expand_one_builtin (CODE_FOR_luc64l, target, exp, code, 2);
6b3d1e47
SC
2809
2810 case IQ2000_BUILTIN_LUK:
5039610b 2811 return expand_one_builtin (CODE_FOR_luk, target, exp, code, 2);
6b3d1e47
SC
2812
2813 case IQ2000_BUILTIN_LULCK:
5039610b 2814 return expand_one_builtin (CODE_FOR_lulck, target, exp, code, 1);
6b3d1e47
SC
2815
2816 case IQ2000_BUILTIN_LUM32:
5039610b 2817 return expand_one_builtin (CODE_FOR_lum32, target, exp, code, 2);
6b3d1e47
SC
2818
2819 case IQ2000_BUILTIN_LUM32L:
5039610b 2820 return expand_one_builtin (CODE_FOR_lum32l, target, exp, code, 2);
6b3d1e47
SC
2821
2822 case IQ2000_BUILTIN_LUM64:
5039610b 2823 return expand_one_builtin (CODE_FOR_lum64, target, exp, code, 2);
6b3d1e47
SC
2824
2825 case IQ2000_BUILTIN_LUM64L:
5039610b 2826 return expand_one_builtin (CODE_FOR_lum64l, target, exp, code, 2);
6b3d1e47
SC
2827
2828 case IQ2000_BUILTIN_LURL:
5039610b 2829 return expand_one_builtin (CODE_FOR_lurl, target, exp, code, 2);
6b3d1e47
SC
2830
2831 case IQ2000_BUILTIN_MRGB:
2832 code[2] = CONST_INT;
5039610b 2833 return expand_one_builtin (CODE_FOR_mrgb, target, exp, code, 3);
6b3d1e47
SC
2834
2835 case IQ2000_BUILTIN_SRRDL:
5039610b 2836 return expand_one_builtin (CODE_FOR_srrdl, target, exp, code, 1);
6b3d1e47
SC
2837
2838 case IQ2000_BUILTIN_SRULCK:
5039610b 2839 return expand_one_builtin (CODE_FOR_srulck, target, exp, code, 1);
6b3d1e47
SC
2840
2841 case IQ2000_BUILTIN_SRWRU:
5039610b 2842 return expand_one_builtin (CODE_FOR_srwru, target, exp, code, 2);
6b3d1e47
SC
2843
2844 case IQ2000_BUILTIN_TRAPQFL:
5039610b 2845 return expand_one_builtin (CODE_FOR_trapqfl, target, exp, code, 0);
6b3d1e47
SC
2846
2847 case IQ2000_BUILTIN_TRAPQNE:
5039610b 2848 return expand_one_builtin (CODE_FOR_trapqne, target, exp, code, 0);
6b3d1e47
SC
2849
2850 case IQ2000_BUILTIN_TRAPREL:
5039610b 2851 return expand_one_builtin (CODE_FOR_traprel, target, exp, code, 1);
6b3d1e47
SC
2852
2853 case IQ2000_BUILTIN_WBU:
5039610b 2854 return expand_one_builtin (CODE_FOR_wbu, target, exp, code, 3);
6b3d1e47
SC
2855
2856 case IQ2000_BUILTIN_SYSCALL:
5039610b 2857 return expand_one_builtin (CODE_FOR_syscall, target, exp, code, 0);
6b3d1e47
SC
2858 }
2859
2860 return NULL_RTX;
2861}
2862\f
bd5bd7ac
KH
2863/* Worker function for TARGET_RETURN_IN_MEMORY. */
2864
69a45040 2865static bool
586de218 2866iq2000_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
69a45040
KH
2867{
2868 return ((int_size_in_bytes (type) > (2 * UNITS_PER_WORD))
2869 || (int_size_in_bytes (type) == -1));
2870}
2871
bd5bd7ac
KH
2872/* Worker function for TARGET_SETUP_INCOMING_VARARGS. */
2873
69a45040 2874static void
d5cc9181 2875iq2000_setup_incoming_varargs (cumulative_args_t cum_v,
ef4bddc2 2876 machine_mode mode ATTRIBUTE_UNUSED,
b5144086
SC
2877 tree type ATTRIBUTE_UNUSED, int * pretend_size,
2878 int no_rtl)
6b3d1e47 2879{
d5cc9181 2880 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
69a45040
KH
2881 unsigned int iq2000_off = ! cum->last_arg_fp;
2882 unsigned int iq2000_fp_off = cum->last_arg_fp;
b5144086 2883
69a45040 2884 if ((cum->arg_words < MAX_ARGS_IN_REGISTERS - iq2000_off))
6b3d1e47
SC
2885 {
2886 int iq2000_save_gp_regs
69a45040 2887 = MAX_ARGS_IN_REGISTERS - cum->arg_words - iq2000_off;
6b3d1e47 2888 int iq2000_save_fp_regs
69a45040 2889 = (MAX_ARGS_IN_REGISTERS - cum->fp_arg_words - iq2000_fp_off);
6b3d1e47
SC
2890
2891 if (iq2000_save_gp_regs < 0)
2892 iq2000_save_gp_regs = 0;
2893 if (iq2000_save_fp_regs < 0)
2894 iq2000_save_fp_regs = 0;
2895
2896 *pretend_size = ((iq2000_save_gp_regs * UNITS_PER_WORD)
2897 + (iq2000_save_fp_regs * UNITS_PER_FPREG));
2898
2899 if (! (no_rtl))
2900 {
69a45040 2901 if (cum->arg_words < MAX_ARGS_IN_REGISTERS - iq2000_off)
6b3d1e47
SC
2902 {
2903 rtx ptr, mem;
0a81f074
RS
2904 ptr = plus_constant (Pmode, virtual_incoming_args_rtx,
2905 - (iq2000_save_gp_regs
2906 * UNITS_PER_WORD));
6b3d1e47
SC
2907 mem = gen_rtx_MEM (BLKmode, ptr);
2908 move_block_from_reg
69a45040 2909 (cum->arg_words + GP_ARG_FIRST + iq2000_off,
6b3d1e47
SC
2910 mem,
2911 iq2000_save_gp_regs);
2912 }
2913 }
2914 }
2915}
2916\f
2917/* A C compound statement to output to stdio stream STREAM the
2918 assembler syntax for an instruction operand that is a memory
b5144086 2919 reference whose address is ADDR. ADDR is an RTL expression. */
6b3d1e47 2920
bf7c1408
NF
2921static void
2922iq2000_print_operand_address (FILE * file, rtx addr)
6b3d1e47
SC
2923{
2924 if (!addr)
2925 error ("PRINT_OPERAND_ADDRESS, null pointer");
2926
2927 else
2928 switch (GET_CODE (addr))
2929 {
2930 case REG:
2931 if (REGNO (addr) == ARG_POINTER_REGNUM)
2932 abort_with_insn (addr, "Arg pointer not eliminated.");
2933
2934 fprintf (file, "0(%s)", reg_names [REGNO (addr)]);
2935 break;
2936
2937 case LO_SUM:
2938 {
b5144086
SC
2939 rtx arg0 = XEXP (addr, 0);
2940 rtx arg1 = XEXP (addr, 1);
6b3d1e47
SC
2941
2942 if (GET_CODE (arg0) != REG)
2943 abort_with_insn (addr,
2944 "PRINT_OPERAND_ADDRESS, LO_SUM with #1 not REG.");
2945
2946 fprintf (file, "%%lo(");
bf7c1408 2947 iq2000_print_operand_address (file, arg1);
6b3d1e47
SC
2948 fprintf (file, ")(%s)", reg_names [REGNO (arg0)]);
2949 }
2950 break;
2951
2952 case PLUS:
2953 {
b5144086
SC
2954 rtx reg = 0;
2955 rtx offset = 0;
2956 rtx arg0 = XEXP (addr, 0);
2957 rtx arg1 = XEXP (addr, 1);
6b3d1e47
SC
2958
2959 if (GET_CODE (arg0) == REG)
2960 {
2961 reg = arg0;
2962 offset = arg1;
2963 if (GET_CODE (offset) == REG)
2964 abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, 2 regs");
2965 }
2966
2967 else if (GET_CODE (arg1) == REG)
2968 reg = arg1, offset = arg0;
2969 else if (CONSTANT_P (arg0) && CONSTANT_P (arg1))
2970 {
2971 output_addr_const (file, addr);
2972 break;
2973 }
2974 else
2975 abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, no regs");
2976
2977 if (! CONSTANT_P (offset))
2978 abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, invalid insn #2");
2979
2980 if (REGNO (reg) == ARG_POINTER_REGNUM)
2981 abort_with_insn (addr, "Arg pointer not eliminated.");
2982
2983 output_addr_const (file, offset);
2984 fprintf (file, "(%s)", reg_names [REGNO (reg)]);
2985 }
2986 break;
2987
2988 case LABEL_REF:
2989 case SYMBOL_REF:
2990 case CONST_INT:
2991 case CONST:
2992 output_addr_const (file, addr);
2993 if (GET_CODE (addr) == CONST_INT)
2994 fprintf (file, "(%s)", reg_names [0]);
2995 break;
2996
2997 default:
2998 abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, invalid insn #1");
2999 break;
3000 }
3001}
3002\f
b5144086
SC
3003/* A C compound statement to output to stdio stream FILE the
3004 assembler syntax for an instruction operand OP.
6b3d1e47 3005
b5144086 3006 LETTER is a value that can be used to specify one of several ways
6b3d1e47 3007 of printing the operand. It is used when identical operands
b5144086 3008 must be printed differently depending on the context. LETTER
6b3d1e47
SC
3009 comes from the `%' specification that was used to request
3010 printing of the operand. If the specification was just `%DIGIT'
b5144086 3011 then LETTER is 0; if the specification was `%LTR DIGIT' then LETTER
6b3d1e47
SC
3012 is the ASCII code for LTR.
3013
b5144086 3014 If OP is a register, this macro should print the register's name.
6b3d1e47
SC
3015 The names can be found in an array `reg_names' whose type is
3016 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
3017
3018 When the machine description has a specification `%PUNCT' (a `%'
3019 followed by a punctuation character), this macro is called with
b5144086 3020 a null pointer for X and the punctuation character for LETTER.
6b3d1e47
SC
3021
3022 The IQ2000 specific codes are:
3023
3024 'X' X is CONST_INT, prints upper 16 bits in hexadecimal format = "0x%04x",
3025 'x' X is CONST_INT, prints lower 16 bits in hexadecimal format = "0x%04x",
3026 'd' output integer constant in decimal,
3027 'z' if the operand is 0, use $0 instead of normal operand.
3028 'D' print second part of double-word register or memory operand.
3029 'L' print low-order register of double-word register operand.
3030 'M' print high-order register of double-word register operand.
3031 'C' print part of opcode for a branch condition.
3032 'F' print part of opcode for a floating-point branch condition.
3033 'N' print part of opcode for a branch condition, inverted.
3034 'W' print part of opcode for a floating-point branch condition, inverted.
3035 'A' Print part of opcode for a bit test condition.
3036 'P' Print label for a bit test.
3037 'p' Print log for a bit test.
3038 'B' print 'z' for EQ, 'n' for NE
3039 'b' print 'n' for EQ, 'z' for NE
3040 'T' print 'f' for EQ, 't' for NE
3041 't' print 't' for EQ, 'f' for NE
3042 'Z' print register and a comma, but print nothing for $fcc0
3043 '?' Print 'l' if we are to use a branch likely instead of normal branch.
3044 '@' Print the name of the assembler temporary register (at or $1).
3045 '.' Print the name of the register with a hard-wired zero (zero or $0).
3046 '$' Print the name of the stack pointer register (sp or $29).
3047 '+' Print the name of the gp register (gp or $28). */
3048
bf7c1408
NF
3049static void
3050iq2000_print_operand (FILE *file, rtx op, int letter)
6b3d1e47 3051{
b5144086 3052 enum rtx_code code;
6b3d1e47 3053
bf7c1408 3054 if (iq2000_print_operand_punct_valid_p (letter))
6b3d1e47
SC
3055 {
3056 switch (letter)
3057 {
3058 case '?':
3059 if (iq2000_branch_likely)
3060 putc ('l', file);
3061 break;
3062
3063 case '@':
3064 fputs (reg_names [GP_REG_FIRST + 1], file);
3065 break;
3066
3067 case '.':
3068 fputs (reg_names [GP_REG_FIRST + 0], file);
3069 break;
3070
3071 case '$':
3072 fputs (reg_names[STACK_POINTER_REGNUM], file);
3073 break;
3074
3075 case '+':
3076 fputs (reg_names[GP_REG_FIRST + 28], file);
3077 break;
3078
3079 default:
3080 error ("PRINT_OPERAND: Unknown punctuation '%c'", letter);
3081 break;
3082 }
3083
3084 return;
3085 }
3086
3087 if (! op)
3088 {
3089 error ("PRINT_OPERAND null pointer");
3090 return;
3091 }
3092
3093 code = GET_CODE (op);
3094
3095 if (code == SIGN_EXTEND)
3096 op = XEXP (op, 0), code = GET_CODE (op);
3097
3098 if (letter == 'C')
3099 switch (code)
3100 {
3101 case EQ: fputs ("eq", file); break;
3102 case NE: fputs ("ne", file); break;
3103 case GT: fputs ("gt", file); break;
3104 case GE: fputs ("ge", file); break;
3105 case LT: fputs ("lt", file); break;
3106 case LE: fputs ("le", file); break;
3107 case GTU: fputs ("ne", file); break;
3108 case GEU: fputs ("geu", file); break;
3109 case LTU: fputs ("ltu", file); break;
3110 case LEU: fputs ("eq", file); break;
3111 default:
3112 abort_with_insn (op, "PRINT_OPERAND, invalid insn for %%C");
3113 }
3114
3115 else if (letter == 'N')
3116 switch (code)
3117 {
3118 case EQ: fputs ("ne", file); break;
3119 case NE: fputs ("eq", file); break;
3120 case GT: fputs ("le", file); break;
3121 case GE: fputs ("lt", file); break;
3122 case LT: fputs ("ge", file); break;
3123 case LE: fputs ("gt", file); break;
3124 case GTU: fputs ("leu", file); break;
3125 case GEU: fputs ("ltu", file); break;
3126 case LTU: fputs ("geu", file); break;
3127 case LEU: fputs ("gtu", file); break;
3128 default:
3129 abort_with_insn (op, "PRINT_OPERAND, invalid insn for %%N");
3130 }
3131
3132 else if (letter == 'F')
3133 switch (code)
3134 {
3135 case EQ: fputs ("c1f", file); break;
3136 case NE: fputs ("c1t", file); break;
3137 default:
3138 abort_with_insn (op, "PRINT_OPERAND, invalid insn for %%F");
3139 }
3140
3141 else if (letter == 'W')
3142 switch (code)
3143 {
3144 case EQ: fputs ("c1t", file); break;
3145 case NE: fputs ("c1f", file); break;
3146 default:
3147 abort_with_insn (op, "PRINT_OPERAND, invalid insn for %%W");
3148 }
3149
3150 else if (letter == 'A')
3151 fputs (code == LABEL_REF ? "i" : "in", file);
3152
3153 else if (letter == 'P')
3154 {
3155 if (code == LABEL_REF)
3156 output_addr_const (file, op);
3157 else if (code != PC)
3158 output_operand_lossage ("invalid %%P operand");
3159 }
3160
3161 else if (letter == 'p')
3162 {
3163 int value;
3164 if (code != CONST_INT
3165 || (value = exact_log2 (INTVAL (op))) < 0)
3166 output_operand_lossage ("invalid %%p value");
954c7446
JR
3167 else
3168 fprintf (file, "%d", value);
6b3d1e47
SC
3169 }
3170
3171 else if (letter == 'Z')
3172 {
292c8018 3173 gcc_unreachable ();
6b3d1e47
SC
3174 }
3175
3176 else if (code == REG || code == SUBREG)
3177 {
b5144086 3178 int regnum;
6b3d1e47
SC
3179
3180 if (code == REG)
3181 regnum = REGNO (op);
3182 else
3183 regnum = true_regnum (op);
3184
3185 if ((letter == 'M' && ! WORDS_BIG_ENDIAN)
3186 || (letter == 'L' && WORDS_BIG_ENDIAN)
3187 || letter == 'D')
3188 regnum++;
3189
3190 fprintf (file, "%s", reg_names[regnum]);
3191 }
3192
3193 else if (code == MEM)
3194 {
3195 if (letter == 'D')
0a81f074 3196 output_address (plus_constant (Pmode, XEXP (op, 0), 4));
6b3d1e47
SC
3197 else
3198 output_address (XEXP (op, 0));
3199 }
3200
3201 else if (code == CONST_DOUBLE
3202 && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT)
3203 {
3204 char s[60];
3205
3206 real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
3207 fputs (s, file);
3208 }
3209
3210 else if (letter == 'x' && GET_CODE (op) == CONST_INT)
3211 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL(op));
3212
3213 else if (letter == 'X' && GET_CODE(op) == CONST_INT)
3214 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & (INTVAL (op) >> 16));
3215
3216 else if (letter == 'd' && GET_CODE(op) == CONST_INT)
3217 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL(op)));
3218
3219 else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
3220 fputs (reg_names[GP_REG_FIRST], file);
3221
3222 else if (letter == 'd' || letter == 'x' || letter == 'X')
3223 output_operand_lossage ("invalid use of %%d, %%x, or %%X");
3224
3225 else if (letter == 'B')
3226 fputs (code == EQ ? "z" : "n", file);
3227 else if (letter == 'b')
3228 fputs (code == EQ ? "n" : "z", file);
3229 else if (letter == 'T')
3230 fputs (code == EQ ? "f" : "t", file);
3231 else if (letter == 't')
3232 fputs (code == EQ ? "t" : "f", file);
3233
3234 else if (code == CONST && GET_CODE (XEXP (op, 0)) == REG)
3235 {
bf7c1408 3236 iq2000_print_operand (file, XEXP (op, 0), letter);
6b3d1e47
SC
3237 }
3238
3239 else
3240 output_addr_const (file, op);
3241}
b5144086 3242
bf7c1408
NF
3243static bool
3244iq2000_print_operand_punct_valid_p (unsigned char code)
3245{
3246 return iq2000_print_operand_punct[code];
3247}
506d7b68
PB
3248
3249/* For the IQ2000, transform:
3250
3251 memory(X + <large int>)
3252 into:
3253 Y = <large int> & ~0x7fff;
3254 Z = X + Y
3255 memory (Z + (<large int> & 0x7fff));
3256*/
3257
3258rtx
3259iq2000_legitimize_address (rtx xinsn, rtx old_x ATTRIBUTE_UNUSED,
ef4bddc2 3260 machine_mode mode)
506d7b68
PB
3261{
3262 if (TARGET_DEBUG_B_MODE)
3263 {
3264 GO_PRINTF ("\n========== LEGITIMIZE_ADDRESS\n");
3265 GO_DEBUG_RTX (xinsn);
3266 }
3267
3268 if (iq2000_check_split (xinsn, mode))
3269 {
3270 return gen_rtx_LO_SUM (Pmode,
3271 copy_to_mode_reg (Pmode,
3272 gen_rtx_HIGH (Pmode, xinsn)),
3273 xinsn);
3274 }
3275
3276 if (GET_CODE (xinsn) == PLUS)
3277 {
3278 rtx xplus0 = XEXP (xinsn, 0);
3279 rtx xplus1 = XEXP (xinsn, 1);
3280 enum rtx_code code0 = GET_CODE (xplus0);
3281 enum rtx_code code1 = GET_CODE (xplus1);
3282
3283 if (code0 != REG && code1 == REG)
3284 {
3285 xplus0 = XEXP (xinsn, 1);
3286 xplus1 = XEXP (xinsn, 0);
3287 code0 = GET_CODE (xplus0);
3288 code1 = GET_CODE (xplus1);
3289 }
3290
3291 if (code0 == REG && REG_MODE_OK_FOR_BASE_P (xplus0, mode)
3292 && code1 == CONST_INT && !SMALL_INT (xplus1))
3293 {
3294 rtx int_reg = gen_reg_rtx (Pmode);
3295 rtx ptr_reg = gen_reg_rtx (Pmode);
3296
3297 emit_move_insn (int_reg,
3298 GEN_INT (INTVAL (xplus1) & ~ 0x7fff));
3299
f7df4a84 3300 emit_insn (gen_rtx_SET (ptr_reg,
506d7b68
PB
3301 gen_rtx_PLUS (Pmode, xplus0, int_reg)));
3302
0a81f074 3303 return plus_constant (Pmode, ptr_reg, INTVAL (xplus1) & 0x7fff);
506d7b68
PB
3304 }
3305 }
3306
3307 if (TARGET_DEBUG_B_MODE)
3308 GO_PRINTF ("LEGITIMIZE_ADDRESS could not fix.\n");
3309
3310 return xinsn;
3311}
3312
3313
b5144086 3314static bool
68f932c4
RS
3315iq2000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
3316 int opno ATTRIBUTE_UNUSED, int * total,
899cc0f4 3317 bool speed ATTRIBUTE_UNUSED)
b5144086 3318{
ef4bddc2 3319 machine_mode mode = GET_MODE (x);
b5144086
SC
3320
3321 switch (code)
3322 {
3323 case MEM:
3324 {
3325 int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
3326
3327 if (simple_memory_operand (x, mode))
3328 return COSTS_N_INSNS (num_words);
3329
3330 * total = COSTS_N_INSNS (2 * num_words);
3331 break;
3332 }
3333
3334 case FFS:
3335 * total = COSTS_N_INSNS (6);
3336 break;
3337
3338 case AND:
3339 case IOR:
3340 case XOR:
3341 case NOT:
3342 * total = COSTS_N_INSNS (mode == DImode ? 2 : 1);
3343 break;
3344
3345 case ASHIFT:
3346 case ASHIFTRT:
3347 case LSHIFTRT:
3348 if (mode == DImode)
3349 * total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT) ? 4 : 12);
3350 else
3351 * total = COSTS_N_INSNS (1);
3352 break;
3353
3354 case ABS:
3355 if (mode == SFmode || mode == DFmode)
3356 * total = COSTS_N_INSNS (1);
3357 else
3358 * total = COSTS_N_INSNS (4);
3359 break;
3360
3361 case PLUS:
3362 case MINUS:
3363 if (mode == SFmode || mode == DFmode)
3364 * total = COSTS_N_INSNS (6);
3365 else if (mode == DImode)
3366 * total = COSTS_N_INSNS (4);
3367 else
3368 * total = COSTS_N_INSNS (1);
3369 break;
3370
3371 case NEG:
3372 * total = (mode == DImode) ? 4 : 1;
3373 break;
3374
3375 case MULT:
3376 if (mode == SFmode)
3377 * total = COSTS_N_INSNS (7);
3378 else if (mode == DFmode)
3379 * total = COSTS_N_INSNS (8);
3380 else
3381 * total = COSTS_N_INSNS (10);
3382 break;
3383
3384 case DIV:
3385 case MOD:
3386 if (mode == SFmode)
3387 * total = COSTS_N_INSNS (23);
3388 else if (mode == DFmode)
3389 * total = COSTS_N_INSNS (36);
3390 else
3391 * total = COSTS_N_INSNS (69);
3392 break;
3393
3394 case UDIV:
3395 case UMOD:
3396 * total = COSTS_N_INSNS (69);
3397 break;
3398
3399 case SIGN_EXTEND:
3400 * total = COSTS_N_INSNS (2);
3401 break;
3402
3403 case ZERO_EXTEND:
3404 * total = COSTS_N_INSNS (1);
3405 break;
3406
3407 case CONST_INT:
3408 * total = 0;
3409 break;
3410
3411 case LABEL_REF:
3412 * total = COSTS_N_INSNS (2);
3413 break;
3414
3415 case CONST:
3416 {
3417 rtx offset = const0_rtx;
3418 rtx symref = eliminate_constant_term (XEXP (x, 0), & offset);
3419
3420 if (GET_CODE (symref) == LABEL_REF)
3421 * total = COSTS_N_INSNS (2);
3422 else if (GET_CODE (symref) != SYMBOL_REF)
3423 * total = COSTS_N_INSNS (4);
5b8d96f1 3424 /* Let's be paranoid.... */
b5144086
SC
3425 else if (INTVAL (offset) < -32768 || INTVAL (offset) > 32767)
3426 * total = COSTS_N_INSNS (2);
3427 else
3428 * total = COSTS_N_INSNS (SYMBOL_REF_FLAG (symref) ? 1 : 2);
3429 break;
3430 }
3431
3432 case SYMBOL_REF:
3433 * total = COSTS_N_INSNS (SYMBOL_REF_FLAG (x) ? 1 : 2);
3434 break;
3435
3436 case CONST_DOUBLE:
3437 {
3438 rtx high, low;
3439
3440 split_double (x, & high, & low);
3441
3442 * total = COSTS_N_INSNS ( (high == CONST0_RTX (GET_MODE (high))
3443 || low == CONST0_RTX (GET_MODE (low)))
3444 ? 2 : 4);
3445 break;
3446 }
3447
3448 default:
3449 return false;
3450 }
3451 return true;
3452}
3453
f4a33d37
RH
3454/* Worker for TARGET_ASM_TRAMPOLINE_TEMPLATE. */
3455
3456static void
3457iq2000_asm_trampoline_template (FILE *f)
3458{
3459 fprintf (f, "\t.word\t0x03e00821\t\t# move $1,$31\n");
3460 fprintf (f, "\t.word\t0x04110001\t\t# bgezal $0,.+8\n");
3461 fprintf (f, "\t.word\t0x00000000\t\t# nop\n");
3462 if (Pmode == DImode)
3463 {
3464 fprintf (f, "\t.word\t0xdfe30014\t\t# ld $3,20($31)\n");
3465 fprintf (f, "\t.word\t0xdfe2001c\t\t# ld $2,28($31)\n");
3466 }
3467 else
3468 {
3469 fprintf (f, "\t.word\t0x8fe30014\t\t# lw $3,20($31)\n");
3470 fprintf (f, "\t.word\t0x8fe20018\t\t# lw $2,24($31)\n");
3471 }
3472 fprintf (f, "\t.word\t0x0060c821\t\t# move $25,$3 (abicalls)\n");
3473 fprintf (f, "\t.word\t0x00600008\t\t# jr $3\n");
3474 fprintf (f, "\t.word\t0x0020f821\t\t# move $31,$1\n");
3475 fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n");
3476 fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n");
3477}
3478
3479/* Worker for TARGET_TRAMPOLINE_INIT. */
3480
3481static void
3482iq2000_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
3483{
3484 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
3485 rtx mem;
3486
3487 emit_block_move (m_tramp, assemble_trampoline_template (),
3488 GEN_INT (TRAMPOLINE_CODE_SIZE), BLOCK_OP_NORMAL);
3489
3490 mem = adjust_address (m_tramp, Pmode, TRAMPOLINE_CODE_SIZE);
3491 emit_move_insn (mem, fnaddr);
3492 mem = adjust_address (m_tramp, Pmode,
3493 TRAMPOLINE_CODE_SIZE + GET_MODE_SIZE (Pmode));
3494 emit_move_insn (mem, chain_value);
3495}
3496
b5144086 3497#include "gt-iq2000.h"