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