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