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