]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/microblaze/microblaze.c
Factor unrelated declarations out of tree.h.
[thirdparty/gcc.git] / gcc / config / microblaze / microblaze.c
CommitLineData
80920132 1/* Subroutines used for code generation on Xilinx MicroBlaze.
d1e082c2 2 Copyright (C) 2009-2013 Free Software Foundation, Inc.
80920132
ME
3
4 Contributed by Michael Eager <eager@eagercon.com>.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
21
22#include "config.h"
23#include "system.h"
24#include "coretypes.h"
80920132
ME
25#include "tm.h"
26#include "rtl.h"
27#include "regs.h"
28#include "hard-reg-set.h"
29#include "real.h"
30#include "insn-config.h"
31#include "conditions.h"
32#include "insn-flags.h"
33#include "insn-attr.h"
80920132 34#include "recog.h"
80920132 35#include "tree.h"
d8a2d370
DN
36#include "varasm.h"
37#include "stor-layout.h"
38#include "calls.h"
80920132
ME
39#include "function.h"
40#include "expr.h"
41#include "flags.h"
42#include "reload.h"
43#include "output.h"
44#include "ggc.h"
45#include "hashtab.h"
46#include "target.h"
47#include "target-def.h"
48#include "tm_p.h"
49#include "gstab.h"
50#include "df.h"
51#include "optabs.h"
52#include "diagnostic-core.h"
a8781821 53#include "cgraph.h"
80920132
ME
54
55#define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
56
57/* Classifies an address.
58
59ADDRESS_INVALID
60An invalid address.
61
62ADDRESS_REG
63
64A natural register or a register + const_int offset address.
65The register satisfies microblaze_valid_base_register_p and the
66offset is a const_arith_operand.
67
68ADDRESS_REG_INDEX
69
70A natural register offset by the index contained in an index register. The base
71register satisfies microblaze_valid_base_register_p and the index register
72satisfies microblaze_valid_index_register_p
73
74ADDRESS_CONST_INT
75
76A signed 16/32-bit constant address.
77
78ADDRESS_SYMBOLIC:
79
80A constant symbolic address or a (register + symbol). */
81
82enum microblaze_address_type
83{
84 ADDRESS_INVALID,
85 ADDRESS_REG,
86 ADDRESS_REG_INDEX,
87 ADDRESS_CONST_INT,
88 ADDRESS_SYMBOLIC,
89 ADDRESS_GOTOFF,
8cc9a5a5
EI
90 ADDRESS_PLT,
91 ADDRESS_TLS
80920132
ME
92};
93
94/* Classifies symbols
95
96SYMBOL_TYPE_GENERAL
97
98A general symbol. */
99enum microblaze_symbol_type
100{
101 SYMBOL_TYPE_INVALID,
102 SYMBOL_TYPE_GENERAL
103};
104
8cc9a5a5
EI
105/* TLS Address Type. */
106enum tls_reloc {
107 TLS_GD,
108 TLS_LDM,
109 TLS_DTPREL,
110 TLS_IE,
111 TLS_LE
112};
113
80920132
ME
114/* Classification of a MicroBlaze address. */
115struct microblaze_address_info
116{
117 enum microblaze_address_type type;
118 rtx regA; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
119 ADDRESS_SYMBOLIC. */
120 rtx regB; /* Contains valid values on ADDRESS_REG_INDEX. */
121 rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
122 rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */
123 enum microblaze_symbol_type symbol_type;
8cc9a5a5 124 enum tls_reloc tls_type;
80920132
ME
125};
126
127/* Structure to be filled in by compute_frame_size with register
128 save masks, and offsets for the current function. */
129
130struct GTY(()) microblaze_frame_info {
131 long total_size; /* # bytes that the entire frame takes up. */
132 long var_size; /* # bytes that variables take up. */
133 long args_size; /* # bytes that outgoing arguments take up. */
134 int link_debug_size; /* # bytes for the link reg and back pointer. */
135 int gp_reg_size; /* # bytes needed to store gp regs. */
136 long gp_offset; /* offset from new sp to store gp registers. */
137 long mask; /* mask of saved gp registers. */
138 int initialized; /* != 0 if frame size already calculated. */
139 int num_gp; /* number of gp registers saved. */
140 long insns_len; /* length of insns. */
141 int alloc_stack; /* Flag to indicate if the current function
142 must not create stack space. (As an optimization). */
143};
144
145/* Global variables for machine-dependent things. */
146
147/* Toggle which pipleline interface to use. */
148static GTY(()) int microblaze_sched_use_dfa = 0;
149
150/* Threshold for data being put into the small data/bss area, instead
151 of the normal data area (references to the small data/bss area take
152 1 instruction, and use the global pointer, references to the normal
153 data area takes 2 instructions). */
154int microblaze_section_threshold = -1;
155
156/* Prevent scheduling potentially exception causing instructions in
157 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
158int microblaze_no_unsafe_delay;
159
c77f83d5
EI
160/* Set to one if the targeted core has the CLZ insn. */
161int microblaze_has_clz = 0;
162
80920132
ME
163/* Which CPU pipeline do we use. We haven't really standardized on a CPU
164 version having only a particular type of pipeline. There can still be
165 options on the CPU to scale pipeline features up or down. :(
166 Bad Presentation (??), so we let the MD file rely on the value of
167 this variable instead Making PIPE_5 the default. It should be backward
168 optimal with PIPE_3 MicroBlazes. */
169enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5;
170
171/* High and low marks for floating point values which we will accept
1a627b35 172 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
80920132
ME
173 initialized in override_options. */
174REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
175
176/* Array giving truth value on whether or not a given hard register
177 can support a given mode. */
178char microblaze_hard_regno_mode_ok[(int)MAX_MACHINE_MODE]
179 [FIRST_PSEUDO_REGISTER];
180
181/* Current frame information calculated by compute_frame_size. */
182struct microblaze_frame_info current_frame_info;
183
184/* Zero structure to initialize current_frame_info. */
185struct microblaze_frame_info zero_frame_info;
186
187/* List of all MICROBLAZE punctuation characters used by print_operand. */
188char microblaze_print_operand_punct[256];
189
190/* Map GCC register number to debugger register number. */
191int microblaze_dbx_regno[FIRST_PSEUDO_REGISTER];
192
193/* Map hard register number to register class. */
194enum reg_class microblaze_regno_to_class[] =
195{
196 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
197 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
198 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
199 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
200 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
201 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
202 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
203 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
204 ST_REGS, GR_REGS, GR_REGS, GR_REGS
205};
206
207/* MicroBlaze specific machine attributes.
208 interrupt_handler - Interrupt handler attribute to add interrupt prologue
209 and epilogue and use appropriate interrupt return.
073a8998 210 save_volatiles - Similar to interrupt handler, but use normal return. */
80920132 211int interrupt_handler;
ee61ea38 212int fast_interrupt;
80920132
ME
213int save_volatiles;
214
215const struct attribute_spec microblaze_attribute_table[] = {
62d784f7
KT
216 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler,
217 affects_type_identity */
218 {"interrupt_handler", 0, 0, true, false, false, NULL,
219 false },
ee61ea38
DH
220 {"fast_interrupt", 0, 0, true, false, false, NULL,
221 false },
62d784f7
KT
222 {"save_volatiles" , 0, 0, true, false, false, NULL,
223 false },
224 { NULL, 0, 0, false, false, false, NULL,
225 false }
80920132
ME
226};
227
228static int microblaze_interrupt_function_p (tree);
229
230section *sdata2_section;
231
8cc9a5a5
EI
232#ifdef HAVE_AS_TLS
233#undef TARGET_HAVE_TLS
234#define TARGET_HAVE_TLS true
235#endif
236
80920132 237/* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
1a627b35 238static bool
80920132
ME
239microblaze_const_double_ok (rtx op, enum machine_mode mode)
240{
241 REAL_VALUE_TYPE d;
242
243 if (GET_CODE (op) != CONST_DOUBLE)
244 return 0;
245
1a627b35 246 if (GET_MODE (op) == VOIDmode)
80920132
ME
247 return 1;
248
249 if (mode != SFmode && mode != DFmode)
250 return 0;
251
252 if (op == CONST0_RTX (mode))
253 return 1;
254
255 REAL_VALUE_FROM_CONST_DOUBLE (d, op);
256
257 if (REAL_VALUE_ISNAN (d))
258 return FALSE;
259
260 if (REAL_VALUE_NEGATIVE (d))
261 d = real_value_negate (&d);
262
263 if (mode == DFmode)
264 {
265 if (REAL_VALUES_LESS (d, dfhigh) && REAL_VALUES_LESS (dflow, d))
266 return 1;
267 }
268 else
269 {
270 if (REAL_VALUES_LESS (d, sfhigh) && REAL_VALUES_LESS (sflow, d))
271 return 1;
272 }
273
274 return 0;
275}
276
277/* Return truth value if a memory operand fits in a single instruction
278 (ie, register + small offset) or (register + register). */
279
280int
281simple_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
282{
283 rtx addr, plus0, plus1;
284
285 /* Eliminate non-memory operations. */
286 if (GET_CODE (op) != MEM)
287 return 0;
288
289 /* dword operations really put out 2 instructions, so eliminate them. */
290 /* ??? This isn't strictly correct. It is OK to accept multiword modes
291 here, since the length attributes are being set correctly, but only
292 if the address is offsettable. */
293 if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)
294 return 0;
295
296
297 /* Decode the address now. */
298 addr = XEXP (op, 0);
299 switch (GET_CODE (addr))
300
301 {
302 case REG:
303 return 1;
304
305 case PLUS:
306 plus0 = XEXP (addr, 0);
307 plus1 = XEXP (addr, 1);
308
8cc9a5a5
EI
309 if (GET_CODE (plus0) != REG)
310 return 0;
311
80920132
ME
312 if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
313 && SMALL_INT (plus1))
314 {
315 return 1;
316 }
317 else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT)
318 {
319 return 1;
320 }
321 else if (GET_CODE (plus0) == REG && GET_CODE (plus1) == REG)
322 {
323 return 1;
324 }
325 else
326 return 0;
327
328 case SYMBOL_REF:
329 return 0;
330
331 default:
332 break;
333 }
334
335 return 0;
336}
337
338/* Return nonzero for a memory address that can be used to load or store
339 a doubleword. */
340
341int
342double_memory_operand (rtx op, enum machine_mode mode)
343{
344 rtx addr;
345
346 if (GET_CODE (op) != MEM || !memory_operand (op, mode))
347 {
348 /* During reload, we accept a pseudo register if it has an
349 appropriate memory address. If we don't do this, we will
350 wind up reloading into a register, and then reloading that
351 register from memory, when we could just reload directly from
352 memory. */
353 if (reload_in_progress
354 && GET_CODE (op) == REG
355 && REGNO (op) >= FIRST_PSEUDO_REGISTER
356 && reg_renumber[REGNO (op)] < 0
f2034d06
JL
357 && reg_equiv_mem (REGNO (op)) != 0
358 && double_memory_operand (reg_equiv_mem (REGNO (op)), mode))
80920132
ME
359 return 1;
360 return 0;
361 }
362
363 /* Make sure that 4 added to the address is a valid memory address.
364 This essentially just checks for overflow in an added constant. */
365
366 addr = XEXP (op, 0);
367
368 if (CONSTANT_ADDRESS_P (addr))
369 return 1;
370
371 return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
0a81f074
RS
372 ? SImode : SFmode),
373 plus_constant (Pmode, addr, 4));
80920132
ME
374}
375
376/* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
377int
378microblaze_regno_ok_for_base_p (int regno, int strict)
379{
380 if (regno >= FIRST_PSEUDO_REGISTER)
381 {
382 if (!strict)
383 return true;
384 regno = reg_renumber[regno];
385 }
386
387 /* These fake registers will be eliminated to either the stack or
388 hard frame pointer, both of which are usually valid base registers.
389 Reload deals with the cases where the eliminated form isn't valid. */
390 if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
391 return true;
392
393 return GP_REG_P (regno);
394}
395
396/* Return true if X is a valid base register for the given mode.
397 Allow only hard registers if STRICT. */
398
399static bool
400microblaze_valid_base_register_p (rtx x,
401 enum machine_mode mode ATTRIBUTE_UNUSED,
402 int strict)
403{
404 if (!strict && GET_CODE (x) == SUBREG)
405 x = SUBREG_REG (x);
406
407 return (GET_CODE (x) == REG
408 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
409}
410
8cc9a5a5
EI
411/* Build the SYMBOL_REF for __tls_get_addr. */
412
413static GTY(()) rtx tls_get_addr_libfunc;
414
415static rtx
416get_tls_get_addr (void)
417{
418 if (!tls_get_addr_libfunc)
419 tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
420 return tls_get_addr_libfunc;
421}
422
423/* Return TRUE if X is a thread-local symbol. */
424bool
425microblaze_tls_symbol_p (rtx x)
426{
427 if (!TARGET_HAVE_TLS)
428 return false;
429
430 if (GET_CODE (x) != SYMBOL_REF)
431 return false;
432
433 return SYMBOL_REF_TLS_MODEL (x) != 0;
434}
435
436static int
437microblaze_tls_operand_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
438{
439 if (GET_CODE (*x) == SYMBOL_REF)
440 return SYMBOL_REF_TLS_MODEL (*x) != 0;
441
442 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
443 TLS offsets, not real symbol references. */
444 if (GET_CODE (*x) == UNSPEC && XINT (*x, 1) == UNSPEC_TLS)
445 return -1;
446
447 return 0;
448}
449
450/* Return TRUE if X contains any TLS symbol references. */
451
452bool
453microblaze_tls_referenced_p (rtx x)
454{
455 if (!TARGET_HAVE_TLS)
456 return false;
457
458 return for_each_rtx (&x, microblaze_tls_operand_p_1, NULL);
459}
460
461bool
462microblaze_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
463{
464 return microblaze_tls_referenced_p(x);
465}
466
467/* Return TRUE if X references a SYMBOL_REF. */
468int
469symbol_mentioned_p (rtx x)
470{
471 const char * fmt;
472 int i;
473
474 if (GET_CODE (x) == SYMBOL_REF)
475 return 1;
476
477 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
478 are constant offsets, not symbols. */
479 if (GET_CODE (x) == UNSPEC)
480 return 0;
481
482 fmt = GET_RTX_FORMAT (GET_CODE (x));
483
484 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
485 {
486 if (fmt[i] == 'E')
487 {
488 int j;
489
490 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
491 if (symbol_mentioned_p (XVECEXP (x, i, j)))
492 return 1;
493 }
494 else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
495 return 1;
496 }
497
498 return 0;
499}
500
501/* Return TRUE if X references a LABEL_REF. */
502int
503label_mentioned_p (rtx x)
504{
505 const char * fmt;
506 int i;
507
508 if (GET_CODE (x) == LABEL_REF)
509 return 1;
510
511 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
512 instruction, but they are constant offsets, not symbols. */
513 if (GET_CODE (x) == UNSPEC)
514 return 0;
515
516 fmt = GET_RTX_FORMAT (GET_CODE (x));
517 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
518 {
519 if (fmt[i] == 'E')
520 {
521 int j;
522
523 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
524 if (label_mentioned_p (XVECEXP (x, i, j)))
525 return 1;
526 }
527 else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
528 return 1;
529 }
530
531 return 0;
532}
533
534int
535tls_mentioned_p (rtx x)
536{
537 switch (GET_CODE (x))
538 {
539 case CONST:
540 return tls_mentioned_p (XEXP (x, 0));
541
542 case UNSPEC:
543 if (XINT (x, 1) == UNSPEC_TLS)
544 return 1;
545
546 default:
547 return 0;
548 }
549}
550
551static rtx
552load_tls_operand (rtx x, rtx reg)
553{
554 rtx tmp;
555
556 if (reg == NULL_RTX)
557 reg = gen_reg_rtx (Pmode);
558
559 tmp = gen_rtx_CONST (Pmode, x);
560
561 emit_insn (gen_rtx_SET (VOIDmode, reg,
562 gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp)));
563
564 return reg;
565}
566
567static rtx
568microblaze_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
569{
570 rtx insns, tls_entry;
571
572 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
573
574 start_sequence ();
575
576 tls_entry = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
577 UNSPEC_TLS);
578
579 reg = load_tls_operand (tls_entry, reg);
580
581 *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX,
582 LCT_PURE, /* LCT_CONST? */
583 Pmode, 1, reg, Pmode);
584
585 insns = get_insns ();
586 end_sequence ();
587
588 return insns;
589}
590
591rtx
592microblaze_legitimize_tls_address(rtx x, rtx reg)
593{
594 rtx dest, insns, ret, eqv, addend;
595 enum tls_model model;
596 model = SYMBOL_REF_TLS_MODEL (x);
597
598 switch (model)
599 {
600 case TLS_MODEL_LOCAL_DYNAMIC:
601 case TLS_MODEL_GLOBAL_DYNAMIC:
602 case TLS_MODEL_INITIAL_EXEC:
603 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_GD);
604 dest = gen_reg_rtx (Pmode);
605 emit_libcall_block (insns, dest, ret, x);
606 break;
607
608 case TLS_MODEL_LOCAL_EXEC:
609 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_LDM);
610
611 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
612 share the LDM result with other LD model accesses. */
613 eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS);
614 dest = gen_reg_rtx (Pmode);
615 emit_libcall_block (insns, dest, ret, eqv);
616
617 /* Load the addend. */
618 addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_DTPREL)),
619 UNSPEC_TLS);
620 addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
621 dest = gen_rtx_PLUS (Pmode, dest, addend);
622 break;
623
624 default:
625 gcc_unreachable ();
626 }
627 return dest;
628}
629
80920132
ME
630static bool
631microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
632{
633 info->symbol_type = SYMBOL_TYPE_GENERAL;
634 info->symbol = XVECEXP (x, 0, 0);
635
636 if (XINT (x, 1) == UNSPEC_GOTOFF)
637 {
638 info->regA = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
639 info->type = ADDRESS_GOTOFF;
640 }
641 else if (XINT (x, 1) == UNSPEC_PLT)
642 {
643 info->type = ADDRESS_PLT;
644 }
8cc9a5a5
EI
645 else if (XINT (x, 1) == UNSPEC_TLS)
646 {
647 info->type = ADDRESS_TLS;
648 info->tls_type = tls_reloc INTVAL(XVECEXP(x, 0, 1));
649 }
80920132
ME
650 else
651 {
652 return false;
653 }
654 return true;
655}
656
657
658/* Return true if X is a valid index register for the given mode.
659 Allow only hard registers if STRICT. */
660
661static bool
662microblaze_valid_index_register_p (rtx x,
663 enum machine_mode mode ATTRIBUTE_UNUSED,
664 int strict)
665{
666 if (!strict && GET_CODE (x) == SUBREG)
667 x = SUBREG_REG (x);
668
669 return (GET_CODE (x) == REG
670 /* A base register is good enough to be an index register on MicroBlaze. */
671 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
672}
673
674/* Get the base register for accessing a value from the memory or
675 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
676static int
677get_base_reg (rtx x)
678{
679 tree decl;
8cc9a5a5
EI
680 int base_reg;
681
682 if (!flag_pic || microblaze_tls_symbol_p(x))
683 base_reg = MB_ABI_BASE_REGNUM;
684 else if (flag_pic)
685 base_reg = MB_ABI_PIC_ADDR_REGNUM;
80920132
ME
686
687 if (TARGET_XLGPOPT
688 && GET_CODE (x) == SYMBOL_REF
689 && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL)
690 {
691 if (TREE_READONLY (decl))
692 base_reg = MB_ABI_GPRO_REGNUM;
693 else
694 base_reg = MB_ABI_GPRW_REGNUM;
695 }
696
697 return base_reg;
698}
699
700/* Return true if X is a valid address for machine mode MODE. If it is,
701 fill in INFO appropriately. STRICT is true if we should only accept
702 hard base registers.
703
704 type regA regB offset symbol
705
706 ADDRESS_INVALID NULL NULL NULL NULL
707
708 ADDRESS_REG %0 NULL const_0 / NULL
709 const_int
710 ADDRESS_REG_INDEX %0 %1 NULL NULL
711
712 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
713 sda_base_reg
714
715 ADDRESS_CONST_INT r0 NULL const NULL
716
717 For modes spanning multiple registers (DFmode in 32-bit GPRs,
718 DImode, TImode), indexed addressing cannot be used because
719 adjacent memory cells are accessed by adding word-sized offsets
720 during assembly output. */
721
722static bool
723microblaze_classify_address (struct microblaze_address_info *info, rtx x,
724 enum machine_mode mode, int strict)
725{
726 rtx xplus0;
727 rtx xplus1;
728
729 info->type = ADDRESS_INVALID;
730 info->regA = NULL;
731 info->regB = NULL;
732 info->offset = NULL;
733 info->symbol = NULL;
734 info->symbol_type = SYMBOL_TYPE_INVALID;
735
736 switch (GET_CODE (x))
737 {
738 case REG:
739 case SUBREG:
740 {
741 info->type = ADDRESS_REG;
742 info->regA = x;
743 info->offset = const0_rtx;
744 return microblaze_valid_base_register_p (info->regA, mode, strict);
745 }
746 case PLUS:
747 {
748 xplus0 = XEXP (x, 0);
749 xplus1 = XEXP (x, 1);
750
751 if (microblaze_valid_base_register_p (xplus0, mode, strict))
752 {
753 info->type = ADDRESS_REG;
754 info->regA = xplus0;
755
756 if (GET_CODE (xplus1) == CONST_INT)
757 {
758 info->offset = xplus1;
759 return true;
760 }
761 else if (GET_CODE (xplus1) == UNSPEC)
762 {
8cc9a5a5
EI
763 /* Need offsettable address. */
764 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
765 return false;
766
80920132
ME
767 return microblaze_classify_unspec (info, xplus1);
768 }
769 else if ((GET_CODE (xplus1) == SYMBOL_REF ||
8cc9a5a5 770 GET_CODE (xplus1) == LABEL_REF))
80920132 771 {
8cc9a5a5
EI
772 if (flag_pic == 2 || microblaze_tls_symbol_p(xplus1))
773 return false;
80920132
ME
774 info->type = ADDRESS_SYMBOLIC;
775 info->symbol = xplus1;
776 info->symbol_type = SYMBOL_TYPE_GENERAL;
777 return true;
778 }
8cc9a5a5
EI
779 else if (GET_CODE (xplus1) == CONST)
780 {
781 rtx xconst0 = XEXP(xplus1, 0);
782
783 /* base + unspec. */
784 if (GET_CODE (xconst0) == UNSPEC)
785 {
786 /* Need offsettable address. */
787 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
788 return false;
789 return microblaze_classify_unspec(info, xconst0);
790 }
791
792 /* for (plus x const_int) just look at x. */
793 if (GET_CODE (xconst0) == PLUS
794 && GET_CODE (XEXP (xconst0, 1)) == CONST_INT
795 && SMALL_INT (XEXP (xconst0, 1)))
796 {
797 /* This is ok as info->symbol is set to xplus1 the full
798 const-expression below. */
799 xconst0 = XEXP (xconst0, 0);
800 }
801
802 if (GET_CODE (xconst0) == SYMBOL_REF
803 || GET_CODE (xconst0) == LABEL_REF)
804 {
805 if (flag_pic == 2 || microblaze_tls_symbol_p(xconst0))
806 return false;
807
808 info->type = ADDRESS_SYMBOLIC;
809 info->symbol = xplus1;
810 info->symbol_type = SYMBOL_TYPE_GENERAL;
811 return true;
812 }
813
814 /* Not base + symbol || base + UNSPEC. */
815 return false;
816
817 }
80920132
ME
818 else if (GET_CODE (xplus1) == REG
819 && microblaze_valid_index_register_p (xplus1, mode,
820 strict)
821 && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
822 {
823 /* Restrict larger than word-width modes from using an index register. */
824 info->type = ADDRESS_REG_INDEX;
825 info->regB = xplus1;
826 return true;
827 }
828 }
829 break;
830 }
831 case CONST_INT:
832 {
833 info->regA = gen_rtx_raw_REG (mode, 0);
834 info->type = ADDRESS_CONST_INT;
835 info->offset = x;
836 return true;
837 }
838 case CONST:
839 case LABEL_REF:
840 case SYMBOL_REF:
841 {
842 info->type = ADDRESS_SYMBOLIC;
843 info->symbol_type = SYMBOL_TYPE_GENERAL;
844 info->symbol = x;
845 info->regA = gen_rtx_raw_REG (mode, get_base_reg (x));
846
847 if (GET_CODE (x) == CONST)
848 {
8cc9a5a5
EI
849 if (GET_CODE (XEXP (x, 0)) == UNSPEC)
850 {
851 info->regA = gen_rtx_raw_REG (mode,
852 get_base_reg (XVECEXP (XEXP (x,0), 0, 0)));
853 return microblaze_classify_unspec (info, XEXP (x, 0));
854 }
855 return !(flag_pic && pic_address_needs_scratch (x));
80920132
ME
856 }
857
8cc9a5a5
EI
858 if (flag_pic == 2)
859 return false;
860 else if (microblaze_tls_symbol_p(x))
861 return false;
862
80920132
ME
863 return true;
864 }
865
866 case UNSPEC:
867 {
868 if (reload_in_progress)
869 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
870 return microblaze_classify_unspec (info, x);
871 }
872
873 default:
874 return false;
875 }
876
877 return false;
878}
879
880/* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
881 returns a nonzero value if X is a legitimate address for a memory
882 operand of the indicated MODE. STRICT is nonzero if this function
883 is called during reload. */
884
885bool
886microblaze_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
887{
888 struct microblaze_address_info addr;
889
890 return microblaze_classify_address (&addr, x, mode, strict);
891}
892
91c4e421
DH
893int
894microblaze_valid_pic_const (rtx x)
895{
896 switch (GET_CODE (x))
897 {
898 case CONST:
899 case CONST_INT:
900 case CONST_DOUBLE:
901 return true;
902 default:
903 return false;
904 }
905}
906
907int
908microblaze_legitimate_pic_operand (rtx x)
909{
8cc9a5a5 910 if (flag_pic == 2 && (symbol_mentioned_p(x) || label_mentioned_p(x)))
91c4e421 911 return 0;
8cc9a5a5
EI
912
913 if (microblaze_tls_referenced_p(x))
91c4e421
DH
914 return 0;
915
916 return 1;
917}
80920132
ME
918
919/* Try machine-dependent ways of modifying an illegitimate address
920 to be legitimate. If we find one, return the new, valid address.
921 This is used from only one place: `memory_address' in explow.c.
922
923 OLDX is the address as it was before break_out_memory_refs was
924 called. In some cases it is useful to look at this to decide what
925 needs to be done.
926
927 It is always safe for this function to do nothing. It exists to
928 recognize opportunities to optimize the output.
929
930 For the MicroBlaze, transform:
931
932 memory(X + <large int>)
933
934 into:
935
936 Y = <large int> & ~0x7fff;
937 Z = X + Y
938 memory (Z + (<large int> & 0x7fff));
939
940 This is for CSE to find several similar references, and only use one Z.
941
942 When PIC, convert addresses of the form memory (symbol+large int) to
943 memory (reg+large int). */
944
945static rtx
946microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
947 enum machine_mode mode ATTRIBUTE_UNUSED)
948{
949 register rtx xinsn = x, result;
950
951 if (GET_CODE (xinsn) == CONST
952 && flag_pic && pic_address_needs_scratch (xinsn))
953 {
954 rtx ptr_reg = gen_reg_rtx (Pmode);
955 rtx constant = XEXP (XEXP (xinsn, 0), 1);
956
957 emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0));
958
959 result = gen_rtx_PLUS (Pmode, ptr_reg, constant);
960 if (SMALL_INT (constant))
961 return result;
962 /* Otherwise we fall through so the code below will fix the
963 constant. */
964 xinsn = result;
965 }
966
967 if (GET_CODE (xinsn) == PLUS)
968 {
969 register rtx xplus0 = XEXP (xinsn, 0);
970 register rtx xplus1 = XEXP (xinsn, 1);
971 register enum rtx_code code0 = GET_CODE (xplus0);
972 register enum rtx_code code1 = GET_CODE (xplus1);
973
974 if (code0 != REG && code1 == REG)
975 {
976 xplus0 = XEXP (xinsn, 1);
977 xplus1 = XEXP (xinsn, 0);
978 code0 = GET_CODE (xplus0);
979 code1 = GET_CODE (xplus1);
980 }
981
982 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)
983 && code1 == CONST_INT && !SMALL_INT (xplus1))
984 {
985 rtx int_reg = gen_reg_rtx (Pmode);
986 rtx ptr_reg = gen_reg_rtx (Pmode);
987
988 emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff));
989
990 emit_insn (gen_rtx_SET (VOIDmode,
991 ptr_reg,
992 gen_rtx_PLUS (Pmode, xplus0, int_reg)));
993
994 result = gen_rtx_PLUS (Pmode, ptr_reg,
995 GEN_INT (INTVAL (xplus1) & 0x7fff));
996 return result;
997 }
998
8cc9a5a5 999 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0))
80920132
ME
1000 {
1001 if (reload_in_progress)
1002 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1003 if (code1 == CONST)
1004 {
1005 xplus1 = XEXP (xplus1, 0);
1006 code1 = GET_CODE (xplus1);
1007 }
1008 if (code1 == SYMBOL_REF)
1009 {
8cc9a5a5
EI
1010 if (microblaze_tls_symbol_p(xplus1))
1011 {
1012 rtx tls_ref, reg;
1013 reg = gen_reg_rtx (Pmode);
1014
1015 tls_ref = microblaze_legitimize_tls_address (xplus1,
1016 NULL_RTX);
1017 emit_move_insn (reg, tls_ref);
1018
1019 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1020
1021 return result;
1022 }
1023 else if (flag_pic == 2)
1024 {
1025 rtx pic_ref, reg;
1026 reg = gen_reg_rtx (Pmode);
1027
1028 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1),
1029 UNSPEC_GOTOFF);
1030 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1031 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1032 pic_ref = gen_const_mem (Pmode, pic_ref);
1033 emit_move_insn (reg, pic_ref);
1034 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1035 return result;
1036 }
80920132
ME
1037 }
1038 }
1039 }
1040
1041 if (GET_CODE (xinsn) == SYMBOL_REF)
1042 {
8cc9a5a5
EI
1043 rtx reg;
1044 if (microblaze_tls_symbol_p(xinsn))
1045 {
1046 reg = microblaze_legitimize_tls_address (xinsn, NULL_RTX);
1047 }
1048 else
1049 {
1050 rtx pic_ref;
1051
1052 if (reload_in_progress)
1053 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1054
1055 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
1056 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1057 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1058 pic_ref = gen_const_mem (Pmode, pic_ref);
1059 reg = pic_ref;
1060 }
1061 return reg;
80920132
ME
1062 }
1063
1064 return x;
1065}
1066
1067/* Block Moves. */
1068
1069#define MAX_MOVE_REGS 8
1070#define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1071
1072/* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1073 Assume that the areas do not overlap. */
1074
1075static void
1076microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
1077{
1078 HOST_WIDE_INT offset, delta;
1079 unsigned HOST_WIDE_INT bits;
1080 int i;
1081 enum machine_mode mode;
1082 rtx *regs;
1083
1084 bits = BITS_PER_WORD;
1085 mode = mode_for_size (bits, MODE_INT, 0);
1086 delta = bits / BITS_PER_UNIT;
1087
1088 /* Allocate a buffer for the temporary registers. */
556618c1 1089 regs = XALLOCAVEC (rtx, length / delta);
80920132
ME
1090
1091 /* Load as many BITS-sized chunks as possible. Use a normal load if
1092 the source has enough alignment, otherwise use left/right pairs. */
1093 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1094 {
1095 regs[i] = gen_reg_rtx (mode);
1096 emit_move_insn (regs[i], adjust_address (src, mode, offset));
1097 }
1098
1099 /* Copy the chunks to the destination. */
1100 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1101 emit_move_insn (adjust_address (dest, mode, offset), regs[i]);
1102
1103 /* Mop up any left-over bytes. */
1104 if (offset < length)
1105 {
1106 src = adjust_address (src, BLKmode, offset);
1107 dest = adjust_address (dest, BLKmode, offset);
1108 move_by_pieces (dest, src, length - offset,
1109 MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), 0);
1110 }
1111}
1112
1113/* Helper function for doing a loop-based block operation on memory
1114 reference MEM. Each iteration of the loop will operate on LENGTH
1115 bytes of MEM.
1116
1117 Create a new base register for use within the loop and point it to
1118 the start of MEM. Create a new memory reference that uses this
1119 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1120
1121static void
1122microblaze_adjust_block_mem (rtx mem, HOST_WIDE_INT length,
1123 rtx * loop_reg, rtx * loop_mem)
1124{
1125 *loop_reg = copy_addr_to_reg (XEXP (mem, 0));
1126
1127 /* Although the new mem does not refer to a known location,
1128 it does keep up to LENGTH bytes of alignment. */
1129 *loop_mem = change_address (mem, BLKmode, *loop_reg);
1130 set_mem_align (*loop_mem,
1131 MIN ((HOST_WIDE_INT) MEM_ALIGN (mem),
1132 length * BITS_PER_UNIT));
1133}
1134
1135
1136/* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1137 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1138 memory regions do not overlap. */
1139
1140static void
1141microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length)
1142{
1143 rtx label, src_reg, dest_reg, final_src;
1144 HOST_WIDE_INT leftover;
1145
1146 leftover = length % MAX_MOVE_BYTES;
1147 length -= leftover;
1148
1149 /* Create registers and memory references for use within the loop. */
1150 microblaze_adjust_block_mem (src, MAX_MOVE_BYTES, &src_reg, &src);
1151 microblaze_adjust_block_mem (dest, MAX_MOVE_BYTES, &dest_reg, &dest);
1152
1153 /* Calculate the value that SRC_REG should have after the last iteration
1154 of the loop. */
1155 final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length),
1156 0, 0, OPTAB_WIDEN);
1157
1158 /* Emit the start of the loop. */
1159 label = gen_label_rtx ();
1160 emit_label (label);
1161
1162 /* Emit the loop body. */
1163 microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES);
1164
1165 /* Move on to the next block. */
0a81f074
RS
1166 emit_move_insn (src_reg, plus_constant (Pmode, src_reg, MAX_MOVE_BYTES));
1167 emit_move_insn (dest_reg, plus_constant (Pmode, dest_reg, MAX_MOVE_BYTES));
80920132
ME
1168
1169 /* Emit the test & branch. */
1170 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src),
1171 src_reg, final_src, label));
1172
1173 /* Mop up any left-over bytes. */
1174 if (leftover)
1175 microblaze_block_move_straight (dest, src, leftover);
1176}
1177
1178/* Expand a movmemsi instruction. */
1179
1180bool
1181microblaze_expand_block_move (rtx dest, rtx src, rtx length, rtx align_rtx)
1182{
1183
1184 if (GET_CODE (length) == CONST_INT)
1185 {
1186 HOST_WIDE_INT bytes = INTVAL (length);
1187 int align = INTVAL (align_rtx);
1188
1189 if (align > UNITS_PER_WORD)
1190 {
1191 align = UNITS_PER_WORD; /* We can't do any better. */
1192 }
1193 else if (align < UNITS_PER_WORD)
1194 {
1195 if (INTVAL (length) <= MAX_MOVE_BYTES)
1196 {
1197 move_by_pieces (dest, src, bytes, align, 0);
1198 return true;
1199 }
1200 else
1201 return false;
1202 }
1203
1204 if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
1205 {
1206 microblaze_block_move_straight (dest, src, INTVAL (length));
1207 return true;
1208 }
1209 else if (optimize)
1210 {
1211 microblaze_block_move_loop (dest, src, INTVAL (length));
1212 return true;
1213 }
1214 }
1215 return false;
1216}
1217
1218static bool
68f932c4
RS
1219microblaze_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
1220 int opno ATTRIBUTE_UNUSED, int *total,
80920132
ME
1221 bool speed ATTRIBUTE_UNUSED)
1222{
1223 enum machine_mode mode = GET_MODE (x);
1224
1225 switch (code)
1226 {
1227 case MEM:
1228 {
1229 int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
1230 if (simple_memory_operand (x, mode))
1231 *total = COSTS_N_INSNS (2 * num_words);
1232 else
1233 *total = COSTS_N_INSNS (2 * (2 * num_words));
1234
1235 return true;
1236 }
1237 case NOT:
1238 {
1239 if (mode == DImode)
1240 {
1241 *total = COSTS_N_INSNS (2);
1242 }
1243 else
1244 *total = COSTS_N_INSNS (1);
1245 return false;
1246 }
1247 case AND:
1248 case IOR:
1249 case XOR:
1250 {
1251 if (mode == DImode)
1252 {
1253 *total = COSTS_N_INSNS (2);
1254 }
1255 else
1256 *total = COSTS_N_INSNS (1);
1257
1258 return false;
1259 }
1260 case ASHIFT:
1261 case ASHIFTRT:
1262 case LSHIFTRT:
1263 {
1264 if (TARGET_BARREL_SHIFT)
1265 {
1266 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1267 >= 0)
1268 *total = COSTS_N_INSNS (1);
1269 else
1270 *total = COSTS_N_INSNS (2);
1271 }
1272 else if (!TARGET_SOFT_MUL)
1273 *total = COSTS_N_INSNS (1);
1274 else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1275 {
1276 /* Add 1 to make shift slightly more expensive than add. */
1277 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1;
cff41484 1278 /* Reduce shift costs for special circumstances. */
80920132
ME
1279 if (optimize_size && INTVAL (XEXP (x, 1)) > 5)
1280 *total -= 2;
1281 if (!optimize_size && INTVAL (XEXP (x, 1)) > 17)
1282 *total -= 2;
1283 }
1284 else
1285 /* Double the worst cost of shifts when there is no barrel shifter and
1286 the shift amount is in a reg. */
1287 *total = COSTS_N_INSNS (32 * 4);
1288 return true;
1289 }
1290 case PLUS:
1291 case MINUS:
1292 {
1293 if (mode == SFmode || mode == DFmode)
1294 {
1295 if (TARGET_HARD_FLOAT)
1296 *total = COSTS_N_INSNS (6);
1297 return true;
1298 }
1299 else if (mode == DImode)
1300 {
1301 *total = COSTS_N_INSNS (4);
1302 return true;
1303 }
1304 else
1305 {
1306 *total = COSTS_N_INSNS (1);
1307 return true;
1308 }
1309
1310 return false;
1311 }
1312 case NEG:
1313 {
1314 if (mode == DImode)
1315 *total = COSTS_N_INSNS (4);
1316
1317 return false;
1318 }
1319 case MULT:
1320 {
1321 if (mode == SFmode)
1322 {
1323 if (TARGET_HARD_FLOAT)
1324 *total = COSTS_N_INSNS (6);
1325 }
1326 else if (!TARGET_SOFT_MUL)
1327 {
1328 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1329 >= 0)
1330 *total = COSTS_N_INSNS (1);
1331 else
1332 *total = COSTS_N_INSNS (3);
1333 }
1334 else
1335 *total = COSTS_N_INSNS (10);
1336 return true;
1337 }
1338 case DIV:
1339 case UDIV:
1340 {
1341 if (mode == SFmode)
1342 {
1343 if (TARGET_HARD_FLOAT)
1344 *total = COSTS_N_INSNS (23);
1345 }
1346 return false;
1347 }
1348 case SIGN_EXTEND:
1349 {
1350 *total = COSTS_N_INSNS (1);
1351 return false;
1352 }
1353 case ZERO_EXTEND:
1354 {
1355 *total = COSTS_N_INSNS (1);
1356 return false;
1357 }
1358 }
1359
1360 return false;
1361}
1362
1363/* Return the number of instructions needed to load or store a value
1364 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1365
1366static int
1367microblaze_address_insns (rtx x, enum machine_mode mode)
1368{
1369 struct microblaze_address_info addr;
1370
1371 if (microblaze_classify_address (&addr, x, mode, false))
1372 {
1373 switch (addr.type)
1374 {
1375 case ADDRESS_REG:
1376 if (SMALL_INT (addr.offset))
1377 return 1;
1378 else
1379 return 2;
1380 case ADDRESS_CONST_INT:
1381 if (SMALL_INT (x))
1382 return 1;
1383 else
1384 return 2;
1385 case ADDRESS_REG_INDEX:
80920132 1386 return 1;
8cc9a5a5 1387 case ADDRESS_SYMBOLIC:
80920132
ME
1388 case ADDRESS_GOTOFF:
1389 return 2;
8cc9a5a5
EI
1390 case ADDRESS_TLS:
1391 switch (addr.tls_type)
1392 {
1393 case TLS_GD:
1394 return 2;
1395 case TLS_LDM:
1396 return 2;
1397 case TLS_DTPREL:
1398 return 1;
1399 default :
1400 abort();
1401 }
80920132
ME
1402 default:
1403 break;
1404 }
1405 }
1406 return 0;
1407}
1408
1409/* Provide the costs of an addressing mode that contains ADDR.
1410 If ADDR is not a valid address, its cost is irrelevant. */
1411static int
b413068c
OE
1412microblaze_address_cost (rtx addr, enum machine_mode mode ATTRIBUTE_UNUSED,
1413 addr_space_t as ATTRIBUTE_UNUSED,
1414 bool speed ATTRIBUTE_UNUSED)
80920132
ME
1415{
1416 return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr)));
1417}
1418
1419/* Return nonzero if X is an address which needs a temporary register when
1420 reloaded while generating PIC code. */
1421
1422int
1423pic_address_needs_scratch (rtx x)
1424{
8cc9a5a5
EI
1425 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
1426 {
1427 rtx p0, p1;
80920132 1428
8cc9a5a5
EI
1429 p0 = XEXP (XEXP (x, 0), 0);
1430 p1 = XEXP (XEXP (x, 0), 1);
1431
1432 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
1433 && (GET_CODE (p1) == CONST_INT)
1434 && (flag_pic == 2 || microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
1435 return 1;
1436 }
80920132
ME
1437 return 0;
1438}
1439
1440/* Argument support functions. */
1441/* Initialize CUMULATIVE_ARGS for a function. */
1442
1443void
1444init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
1445 rtx libname ATTRIBUTE_UNUSED)
1446{
1447 static CUMULATIVE_ARGS zero_cum;
1448 tree param, next_param;
1449
1450 *cum = zero_cum;
1451
1452 /* Determine if this function has variable arguments. This is
1453 indicated by the last argument being 'void_type_mode' if there
1454 are no variable arguments. The standard MicroBlaze calling sequence
1455 passes all arguments in the general purpose registers in this case. */
1456
1457 for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
1458 param != 0; param = next_param)
1459 {
1460 next_param = TREE_CHAIN (param);
1461 if (next_param == 0 && TREE_VALUE (param) != void_type_node)
1462 cum->gp_reg_found = 1;
1463 }
1464}
1465
1466/* Advance the argument to the next argument position. */
1467
5239874d 1468static void
d5cc9181
JR
1469microblaze_function_arg_advance (cumulative_args_t cum_v,
1470 enum machine_mode mode,
5239874d 1471 const_tree type, bool named ATTRIBUTE_UNUSED)
80920132 1472{
d5cc9181
JR
1473 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1474
80920132
ME
1475 cum->arg_number++;
1476 switch (mode)
1477 {
1478 case VOIDmode:
1479 break;
1480
1481 default:
1482 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1483 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1484
1485 cum->gp_reg_found = 1;
1486 cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
1487 / UNITS_PER_WORD);
1488 break;
1489
1490 case BLKmode:
1491 cum->gp_reg_found = 1;
1492 cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1493 / UNITS_PER_WORD);
1494 break;
1495
1496 case SFmode:
1497 cum->arg_words++;
1498 if (!cum->gp_reg_found && cum->arg_number <= 2)
1499 cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
1500 break;
1501
1502 case DFmode:
1503 cum->arg_words += 2;
1504 if (!cum->gp_reg_found && cum->arg_number <= 2)
1505 cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
1506 break;
1507
1508 case DImode:
1509 cum->gp_reg_found = 1;
1510 cum->arg_words += 2;
1511 break;
1512
1513 case QImode:
1514 case HImode:
1515 case SImode:
1516 case TImode:
1517 cum->gp_reg_found = 1;
1518 cum->arg_words++;
1519 break;
1520 }
1521}
1522
1523/* Return an RTL expression containing the register for the given mode,
1524 or 0 if the argument is to be passed on the stack. */
1525
5239874d 1526static rtx
d5cc9181 1527microblaze_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
5239874d
NF
1528 const_tree type ATTRIBUTE_UNUSED,
1529 bool named ATTRIBUTE_UNUSED)
80920132 1530{
d5cc9181
JR
1531 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1532
80920132
ME
1533 rtx ret;
1534 int regbase = -1;
1535 int *arg_words = &cum->arg_words;
1536
1537 cum->last_arg_fp = 0;
1538 switch (mode)
1539 {
1540 case SFmode:
1541 case DFmode:
1542 case VOIDmode:
1543 case QImode:
1544 case HImode:
1545 case SImode:
1546 case DImode:
1547 case TImode:
1548 regbase = GP_ARG_FIRST;
1549 break;
1550 default:
1551 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1552 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1553 /* Drops through. */
1554 case BLKmode:
1555 regbase = GP_ARG_FIRST;
1556 break;
1557 }
1558
1559 if (*arg_words >= MAX_ARGS_IN_REGISTERS)
1560 ret = 0;
1561 else
1562 {
1563 gcc_assert (regbase != -1);
1564
1565 ret = gen_rtx_REG (mode, regbase + *arg_words);
1566 }
1567
1568 if (mode == VOIDmode)
1569 {
1570 if (cum->num_adjusts > 0)
1571 ret = gen_rtx_PARALLEL ((enum machine_mode) cum->fp_code,
1572 gen_rtvec_v (cum->num_adjusts, cum->adjust));
1573 }
1574
1575 return ret;
1576}
1577
1578/* Return number of bytes of argument to put in registers. */
1579static int
d5cc9181 1580function_arg_partial_bytes (cumulative_args_t cum_v, enum machine_mode mode,
80920132
ME
1581 tree type, bool named ATTRIBUTE_UNUSED)
1582{
d5cc9181
JR
1583 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1584
80920132
ME
1585 if ((mode == BLKmode
1586 || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
1587 || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
1588 && cum->arg_words < MAX_ARGS_IN_REGISTERS)
1589 {
1590 int words;
1591 if (mode == BLKmode)
1592 words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1593 / UNITS_PER_WORD);
1594 else
1595 words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1596
1597 if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
1598 return 0; /* structure fits in registers */
1599
1600 return (MAX_ARGS_IN_REGISTERS - cum->arg_words) * UNITS_PER_WORD;
1601 }
1602
1603 else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1)
1604 return UNITS_PER_WORD;
1605
1606 return 0;
1607}
1608
1609/* Convert a version number of the form "vX.YY.Z" to an integer encoding
1610 for easier range comparison. */
1611static int
1612microblaze_version_to_int (const char *version)
1613{
1614 const char *p, *v;
1615 const char *tmpl = "vX.YY.Z";
1616 int iver = 0;
1617
1618 p = version;
1619 v = tmpl;
1620
1621 while (*v)
1622 {
1623 if (*v == 'X')
1624 { /* Looking for major */
1625 if (!(*p >= '0' && *p <= '9'))
1626 return -1;
1627 iver += (int) (*p - '0');
1628 iver *= 10;
1629 }
1630 else if (*v == 'Y')
1631 { /* Looking for minor */
1632 if (!(*p >= '0' && *p <= '9'))
1633 return -1;
1634 iver += (int) (*p - '0');
1635 iver *= 10;
1636 }
1637 else if (*v == 'Z')
1638 { /* Looking for compat */
1639 if (!(*p >= 'a' && *p <= 'z'))
1640 return -1;
1641 iver *= 10;
1642 iver += (int) (*p - 'a');
1643 }
1644 else
1645 {
1646 if (*p != *v)
1647 return -1;
1648 }
1649
1650 v++;
1651 p++;
1652 }
1653
1654 if (*p)
1655 return -1;
1656
1657 return iver;
1658}
1659
80920132
ME
1660
1661static void
1662microblaze_option_override (void)
1663{
1664 register int i, start;
1665 register int regno;
1666 register enum machine_mode mode;
1667 int ver;
1668
fa37ed29
JM
1669 microblaze_section_threshold = (global_options_set.x_g_switch_value
1670 ? g_switch_value
1671 : MICROBLAZE_DEFAULT_GVALUE);
80920132 1672
debd11d9
EI
1673 if (flag_pic)
1674 {
1675 /* Make sure it's 2, we only support one kind of PIC. */
1676 flag_pic = 2;
1677 if (!TARGET_SUPPORTS_PIC)
1678 {
1679 error ("-fPIC/-fpic not supported for this target");
1680 /* Clear it to avoid further errors. */
1681 flag_pic = 0;
1682 }
1683 }
1684
80920132
ME
1685 /* Check the MicroBlaze CPU version for any special action to be done. */
1686 if (microblaze_select_cpu == NULL)
1687 microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU;
1688 ver = microblaze_version_to_int (microblaze_select_cpu);
1689 if (ver == -1)
1690 {
1691 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu);
1692 }
1693
1694 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v3.00.a");
1695 if (ver < 0)
1696 {
1697 /* No hardware exceptions in earlier versions. So no worries. */
556618c1
JR
1698#if 0
1699 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1700#endif
80920132
ME
1701 microblaze_no_unsafe_delay = 0;
1702 microblaze_pipe = MICROBLAZE_PIPE_3;
1703 }
1704 else if (ver == 0
1705 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b")
1706 == 0))
1707 {
556618c1
JR
1708#if 0
1709 microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1710#endif
80920132
ME
1711 microblaze_no_unsafe_delay = 1;
1712 microblaze_pipe = MICROBLAZE_PIPE_3;
1713 }
1714 else
1715 {
1716 /* We agree to use 5 pipe-stage model even on area optimized 3
1717 pipe-stage variants. */
556618c1
JR
1718#if 0
1719 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1720#endif
80920132
ME
1721 microblaze_no_unsafe_delay = 0;
1722 microblaze_pipe = MICROBLAZE_PIPE_5;
1723 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0
1724 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1725 "v5.00.b") == 0
1726 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1727 "v5.00.c") == 0)
1728 {
1729 /* Pattern compares are to be turned on by default only when
1730 compiling for MB v5.00.'z'. */
1731 target_flags |= MASK_PATTERN_COMPARE;
1732 }
1733 }
1734
1735 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a");
1736 if (ver < 0)
1737 {
1738 if (TARGET_MULTIPLY_HIGH)
1739 warning (0,
1740 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1741 }
1742
c77f83d5
EI
1743 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.10.a");
1744 microblaze_has_clz = 1;
1745 if (ver < 0)
1746 {
1747 /* MicroBlaze prior to 8.10.a didn't have clz. */
1748 microblaze_has_clz = 0;
1749 }
1750
cb8a1637
DH
1751 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1752 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.30.a");
1753 if (ver < 0)
1754 {
1755 if (TARGET_REORDER == 1)
1756 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1757 TARGET_REORDER = 0;
1758 }
1759 else if ((ver == 0) && !TARGET_PATTERN_COMPARE)
1760 {
1761 if (TARGET_REORDER == 1)
1762 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1763 TARGET_REORDER = 0;
1764 }
1765
80920132
ME
1766 if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
1767 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1768
1769 /* Always use DFA scheduler. */
1770 microblaze_sched_use_dfa = 1;
1771
556618c1
JR
1772#if 0
1773 microblaze_abicalls = MICROBLAZE_ABICALLS_NO;
1774#endif
80920132
ME
1775
1776 /* Initialize the high, low values for legit floating point constants. */
1777 real_maxval (&dfhigh, 0, DFmode);
1778 real_maxval (&dflow, 1, DFmode);
1779 real_maxval (&sfhigh, 0, SFmode);
1780 real_maxval (&sflow, 1, SFmode);
1781
1782 microblaze_print_operand_punct['?'] = 1;
1783 microblaze_print_operand_punct['#'] = 1;
1784 microblaze_print_operand_punct['&'] = 1;
1785 microblaze_print_operand_punct['!'] = 1;
1786 microblaze_print_operand_punct['*'] = 1;
1787 microblaze_print_operand_punct['@'] = 1;
1788 microblaze_print_operand_punct['.'] = 1;
1789 microblaze_print_operand_punct['('] = 1;
1790 microblaze_print_operand_punct[')'] = 1;
1791 microblaze_print_operand_punct['['] = 1;
1792 microblaze_print_operand_punct[']'] = 1;
1793 microblaze_print_operand_punct['<'] = 1;
1794 microblaze_print_operand_punct['>'] = 1;
1795 microblaze_print_operand_punct['{'] = 1;
1796 microblaze_print_operand_punct['}'] = 1;
1797 microblaze_print_operand_punct['^'] = 1;
1798 microblaze_print_operand_punct['$'] = 1;
1799 microblaze_print_operand_punct['+'] = 1;
1800
1801 /* Set up array to map GCC register number to debug register number.
1802 Ignore the special purpose register numbers. */
1803
1804 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1805 microblaze_dbx_regno[i] = -1;
1806
1807 start = GP_DBX_FIRST - GP_REG_FIRST;
1808 for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
1809 microblaze_dbx_regno[i] = i + start;
1810
1811 /* Set up array giving whether a given register can hold a given mode. */
1812
1813 for (mode = VOIDmode;
1814 mode != MAX_MACHINE_MODE; mode = (enum machine_mode) ((int) mode + 1))
1815 {
1816 register int size = GET_MODE_SIZE (mode);
1817
1818 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1819 {
1820 register int ok;
1821
1822 if (mode == CCmode)
1823 {
1824 ok = (ST_REG_P (regno) || GP_REG_P (regno));
1825 }
1826 else if (GP_REG_P (regno))
1827 ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
1828 else
1829 ok = 0;
1830
1831 microblaze_hard_regno_mode_ok[(int) mode][regno] = ok;
1832 }
1833 }
1834}
1835
1836/* Return true if FUNC is an interrupt function as specified
1837 by the "interrupt_handler" attribute. */
1838
1839static int
1840microblaze_interrupt_function_p (tree func)
1841{
1842 tree a;
1843
1844 if (TREE_CODE (func) != FUNCTION_DECL)
1845 return 0;
1846
1847 a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
1848 return a != NULL_TREE;
1849}
1850
ee61ea38
DH
1851static int
1852microblaze_fast_interrupt_function_p (tree func)
1853{
1854 tree a;
1855
1856 if (TREE_CODE (func) != FUNCTION_DECL)
1857 return 0;
1858
1859 a = lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func));
1860 return a != NULL_TREE;
1861}
1862
80920132
ME
1863/* Return true if FUNC is an interrupt function which uses
1864 normal return, indicated by the "save_volatiles" attribute. */
1865
1866static int
1867microblaze_save_volatiles (tree func)
1868{
1869 tree a;
1870
1871 if (TREE_CODE (func) != FUNCTION_DECL)
1872 return 0;
1873
1874 a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
1875 return a != NULL_TREE;
1876}
1877
1878/* Return whether function is tagged with 'interrupt_handler'
ee61ea38
DH
1879 or 'fast_interrupt' attribute. Return true if function
1880 should use return from interrupt rather than normal
1881 function return. */
80920132 1882int
ee61ea38 1883microblaze_is_interrupt_variant (void)
80920132 1884{
ee61ea38 1885 return (interrupt_handler || fast_interrupt);
80920132
ME
1886}
1887
1888/* Determine of register must be saved/restored in call. */
1889static int
1890microblaze_must_save_register (int regno)
1891{
1892 if (pic_offset_table_rtx &&
1893 (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno))
1894 return 1;
1895
1896 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1897 return 1;
1898
1899 if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
1900 return 1;
1901
416ff32e 1902 if (!crtl->is_leaf)
80920132
ME
1903 {
1904 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1905 return 1;
ee61ea38 1906 if ((microblaze_is_interrupt_variant () || save_volatiles) &&
80920132
ME
1907 (regno >= 3 && regno <= 12))
1908 return 1;
1909 }
1910
ee61ea38 1911 if (microblaze_is_interrupt_variant ())
80920132
ME
1912 {
1913 if (df_regs_ever_live_p (regno)
1914 || regno == MB_ABI_MSR_SAVE_REG
ee61ea38
DH
1915 || (interrupt_handler
1916 && (regno == MB_ABI_ASM_TEMP_REGNUM
1917 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)))
80920132
ME
1918 return 1;
1919 }
1920
1921 if (save_volatiles)
1922 {
1923 if (df_regs_ever_live_p (regno)
1924 || regno == MB_ABI_ASM_TEMP_REGNUM
1925 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1926 return 1;
1927 }
1928
1929 return 0;
1930}
1931
1932/* Return the bytes needed to compute the frame pointer from the current
1933 stack pointer.
1934
1935 MicroBlaze stack frames look like:
1936
1937
1938
1939 Before call After call
1940 +-----------------------+ +-----------------------+
1941 high | | | |
1942 mem. | local variables, | | local variables, |
1943 | callee saved and | | callee saved and |
1944 | temps | | temps |
1945 +-----------------------+ +-----------------------+
1946 | arguments for called | | arguments for called |
1947 | subroutines | | subroutines |
1948 | (optional) | | (optional) |
1949 +-----------------------+ +-----------------------+
1950 | Link register | | Link register |
1951 SP->| | | |
1952 +-----------------------+ +-----------------------+
1953 | |
1954 | local variables, |
1955 | callee saved and |
1956 | temps |
1957 +-----------------------+
1958 | MSR (optional if, |
1959 | interrupt handler) |
1960 +-----------------------+
1961 | |
1962 | alloca allocations |
1963 | |
1964 +-----------------------+
1965 | |
1966 | arguments for called |
1967 | subroutines |
1968 | (optional) |
1969 | |
1970 +-----------------------+
1971 | Link register |
1972 low FP,SP->| |
1973 memory +-----------------------+
1974
1975*/
1976
1977static HOST_WIDE_INT
1978compute_frame_size (HOST_WIDE_INT size)
1979{
1980 int regno;
1981 HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
1982 HOST_WIDE_INT var_size; /* # bytes that local variables take up. */
1983 HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */
1984 int link_debug_size; /* # bytes for link register. */
1985 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */
1986 long mask; /* mask of saved gp registers. */
1987
1988 interrupt_handler =
1989 microblaze_interrupt_function_p (current_function_decl);
ee61ea38
DH
1990 fast_interrupt =
1991 microblaze_fast_interrupt_function_p (current_function_decl);
80920132
ME
1992 save_volatiles = microblaze_save_volatiles (current_function_decl);
1993
1994 gp_reg_size = 0;
1995 mask = 0;
1996 var_size = size;
1997 args_size = crtl->outgoing_args_size;
1998
1999 if ((args_size == 0) && cfun->calls_alloca)
2000 args_size = NUM_OF_ARGS * UNITS_PER_WORD;
2001
2002 total_size = var_size + args_size;
2003
2004 if (flag_pic == 2)
2005 /* force setting GOT. */
2006 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true);
2007
2008 /* Calculate space needed for gp registers. */
2009 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2010 {
2011 if (microblaze_must_save_register (regno))
2012 {
2013
2014 if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM)
2015 /* Don't account for link register. It is accounted specially below. */
2016 gp_reg_size += GET_MODE_SIZE (SImode);
2017
2018 mask |= (1L << (regno - GP_REG_FIRST));
2019 }
2020 }
2021
2022 total_size += gp_reg_size;
2023
2024 /* Add 4 bytes for MSR. */
ee61ea38 2025 if (microblaze_is_interrupt_variant ())
80920132
ME
2026 total_size += 4;
2027
2028 /* No space to be allocated for link register in leaf functions with no other
2029 stack requirements. */
416ff32e 2030 if (total_size == 0 && crtl->is_leaf)
80920132
ME
2031 link_debug_size = 0;
2032 else
2033 link_debug_size = UNITS_PER_WORD;
2034
2035 total_size += link_debug_size;
2036
2037 /* Save other computed information. */
2038 current_frame_info.total_size = total_size;
2039 current_frame_info.var_size = var_size;
2040 current_frame_info.args_size = args_size;
2041 current_frame_info.gp_reg_size = gp_reg_size;
2042 current_frame_info.mask = mask;
2043 current_frame_info.initialized = reload_completed;
2044 current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
2045 current_frame_info.link_debug_size = link_debug_size;
2046
2047 if (mask)
2048 /* Offset from which to callee-save GP regs. */
2049 current_frame_info.gp_offset = (total_size - gp_reg_size);
2050 else
2051 current_frame_info.gp_offset = 0;
2052
2053 /* Ok, we're done. */
2054 return total_size;
2055}
2056
2057/* Make sure that we're not trying to eliminate to the wrong hard frame
2058 pointer. */
2059
2060static bool
2061microblaze_can_eliminate (const int from, const int to)
2062{
2063 return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p())
2064 || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p())
2065 || (from != RETURN_ADDRESS_POINTER_REGNUM
2066 && (to == HARD_FRAME_POINTER_REGNUM
2067 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed))));
2068}
2069
2070/* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2071 pointer or argument pointer or the return address pointer. TO is either
2072 the stack pointer or hard frame pointer. */
2073
2074HOST_WIDE_INT
2075microblaze_initial_elimination_offset (int from, int to)
2076{
2077 HOST_WIDE_INT offset;
2078
2079 switch (from)
2080 {
2081 case FRAME_POINTER_REGNUM:
2082 offset = 0;
2083 break;
2084 case ARG_POINTER_REGNUM:
2085 if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM)
2086 offset = compute_frame_size (get_frame_size ());
2087 else
2088 gcc_unreachable ();
2089 break;
2090 case RETURN_ADDRESS_POINTER_REGNUM:
416ff32e 2091 if (crtl->is_leaf)
80920132
ME
2092 offset = 0;
2093 else
2094 offset = current_frame_info.gp_offset +
2095 ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
2096 break;
2097 default:
2098 gcc_unreachable ();
2099 }
2100 return offset;
2101}
2102
2103/* Print operands using format code.
2104
2105 The MicroBlaze specific codes are:
2106
2107 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2108 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2109 'F' op is CONST_DOUBLE, print 32 bits in hex,
2110 'd' output integer constant in decimal,
2111 'z' if the operand is 0, use $0 instead of normal operand.
2112 'D' print second register of double-word register operand.
2113 'L' print low-order register of double-word register operand.
2114 'M' print high-order register of double-word register operand.
2115 'C' print part of opcode for a branch condition.
2116 'N' print part of opcode for a branch condition, inverted.
2117 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2118 'B' print 'z' for EQ, 'n' for NE
2119 'b' print 'n' for EQ, 'z' for NE
2120 'T' print 'f' for EQ, 't' for NE
2121 't' print 't' for EQ, 'f' for NE
2122 'm' Print 1<<operand.
2123 'i' Print 'i' if MEM operand has immediate value
450b0ebb 2124 'y' Print 'y' if MEM operand is single register
80920132
ME
2125 'o' Print operand address+4
2126 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2127 'h' Print high word of const_double (int or float) value as hex
2128 'j' Print low word of const_double (int or float) value as hex
2129 's' Print -1 if operand is negative, 0 if positive (sign extend)
2130 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2131 '#' Print nop if the delay slot of a branch is not filled.
2132*/
2133
2134void
2135print_operand (FILE * file, rtx op, int letter)
2136{
2137 register enum rtx_code code;
2138
2139 if (PRINT_OPERAND_PUNCT_VALID_P (letter))
2140 {
2141 switch (letter)
2142 {
2143 case '?':
2144 /* Conditionally add a 'd' to indicate filled delay slot. */
2145 if (final_sequence != NULL)
2146 fputs ("d", file);
2147 break;
2148
2149 case '#':
2150 /* Conditionally add a nop in unfilled delay slot. */
2151 if (final_sequence == NULL)
2152 fputs ("nop\t\t# Unfilled delay slot\n", file);
2153 break;
2154
2155 case '@':
2156 fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file);
2157 break;
2158
2159 default:
2160 output_operand_lossage ("unknown punctuation '%c'", letter);
2161 break;
2162 }
2163
2164 return;
2165 }
2166
2167 if (!op)
2168 {
2169 output_operand_lossage ("null pointer");
2170 return;
2171 }
2172
2173 code = GET_CODE (op);
2174
2175 if (code == SIGN_EXTEND)
2176 op = XEXP (op, 0), code = GET_CODE (op);
2177
2178 if (letter == 'C')
2179 switch (code)
2180 {
2181 case EQ:
2182 fputs ("eq", file);
2183 break;
2184 case NE:
2185 fputs ("ne", file);
2186 break;
2187 case GT:
2188 case GTU:
2189 fputs ("gt", file);
2190 break;
2191 case GE:
2192 case GEU:
2193 fputs ("ge", file);
2194 break;
2195 case LT:
2196 case LTU:
2197 fputs ("lt", file);
2198 break;
2199 case LE:
2200 case LEU:
2201 fputs ("le", file);
2202 break;
2203 default:
2204 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op);
2205 }
2206
2207 else if (letter == 'N')
2208 switch (code)
2209 {
2210 case EQ:
2211 fputs ("ne", file);
2212 break;
2213 case NE:
2214 fputs ("eq", file);
2215 break;
2216 case GT:
2217 case GTU:
2218 fputs ("le", file);
2219 break;
2220 case GE:
2221 case GEU:
2222 fputs ("lt", file);
2223 break;
2224 case LT:
2225 case LTU:
2226 fputs ("ge", file);
2227 break;
2228 case LE:
2229 case LEU:
2230 fputs ("gt", file);
2231 break;
2232 default:
2233 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op);
2234 }
2235
2236 else if (letter == 'S')
2237 {
2238 char buffer[100];
2239
2240 ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
2241 assemble_name (file, buffer);
2242 }
2243
2244 /* Print 'i' for memory operands which have immediate values. */
2245 else if (letter == 'i')
2246 {
2247 if (code == MEM)
2248 {
2249 struct microblaze_address_info info;
2250
2251 if (!microblaze_classify_address
2252 (&info, XEXP (op, 0), GET_MODE (op), 1))
2253 fatal_insn ("insn contains an invalid address !", op);
2254
2255 switch (info.type)
2256 {
2257 case ADDRESS_REG:
2258 case ADDRESS_CONST_INT:
2259 case ADDRESS_SYMBOLIC:
2260 case ADDRESS_GOTOFF:
8cc9a5a5 2261 case ADDRESS_TLS:
80920132
ME
2262 fputs ("i", file);
2263 break;
2264 case ADDRESS_REG_INDEX:
2265 break;
2266 case ADDRESS_INVALID:
2267 case ADDRESS_PLT:
d8a07487 2268 fatal_insn ("invalid address", op);
80920132
ME
2269 }
2270 }
2271 }
2272
2273 else if (code == REG || code == SUBREG)
2274 {
2275 register int regnum;
2276
2277 if (code == REG)
2278 regnum = REGNO (op);
2279 else
2280 regnum = true_regnum (op);
2281
2282 if ((letter == 'M' && !WORDS_BIG_ENDIAN)
2283 || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D')
2284 regnum++;
2285
2286 fprintf (file, "%s", reg_names[regnum]);
2287 }
2288
2289 else if (code == MEM)
2290 if (letter == 'o')
2291 {
2292 rtx op4 = adjust_address (op, GET_MODE (op), 4);
2293 output_address (XEXP (op4, 0));
2294 }
450b0ebb
DH
2295 else if (letter == 'y')
2296 {
2297 rtx mem_reg = XEXP (op, 0);
2298 if (GET_CODE (mem_reg) == REG)
2299 {
2300 register int regnum = REGNO (mem_reg);
2301 fprintf (file, "%s", reg_names[regnum]);
2302 }
2303 }
80920132
ME
2304 else
2305 output_address (XEXP (op, 0));
2306
2307 else if (letter == 'h' || letter == 'j')
2308 {
2309 long val[2];
2310 if (code == CONST_DOUBLE)
2311 {
2312 if (GET_MODE (op) == DFmode)
2313 {
2314 REAL_VALUE_TYPE value;
2315 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
2316 REAL_VALUE_TO_TARGET_DOUBLE (value, val);
2317 }
2318 else
2319 {
2320 val[0] = CONST_DOUBLE_HIGH (op);
2321 val[1] = CONST_DOUBLE_LOW (op);
2322 }
2323 }
2324 else if (code == CONST_INT)
2325 {
2326 val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32;
2327 val[1] = INTVAL (op) & 0x00000000ffffffffLL;
2328 if (val[0] == 0 && val[1] < 0)
2329 val[0] = -1;
2330
2331 }
2332 fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]);
2333 }
2334 else if (code == CONST_DOUBLE)
2335 {
2336 if (letter == 'F')
2337 {
2338 unsigned long value_long;
2339 REAL_VALUE_TYPE value;
2340 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
2341 REAL_VALUE_TO_TARGET_SINGLE (value, value_long);
2342 fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long);
2343 }
2344 else
2345 {
2346 char s[60];
2347 real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
2348 fputs (s, file);
2349 }
2350 }
2351
2352 else if (code == UNSPEC)
2353 {
2354 print_operand_address (file, op);
2355 }
2356
2357 else if (letter == 'x' && GET_CODE (op) == CONST_INT)
2358 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op));
2359
2360 else if (letter == 'X' && GET_CODE (op) == CONST_INT)
2361 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
2362
2363 else if (letter == 'd' && GET_CODE (op) == CONST_INT)
2364 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op)));
2365
2366 else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
2367 fputs (reg_names[GP_REG_FIRST], file);
2368
2369 else if (letter == 's' && GET_CODE (op) == CONST_INT)
2370 if (INTVAL (op) < 0)
2371 fputs ("-1", file);
2372 else
2373 fputs ("0", file);
2374
2375 else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's')
2376 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter);
2377
2378 else if (letter == 'B')
2379 fputs (code == EQ ? "z" : "n", file);
2380 else if (letter == 'b')
2381 fputs (code == EQ ? "n" : "z", file);
2382 else if (letter == 'T')
2383 fputs (code == EQ ? "f" : "t", file);
2384 else if (letter == 't')
2385 fputs (code == EQ ? "t" : "f", file);
2386
8cc9a5a5
EI
2387 else if (code == CONST
2388 && ((GET_CODE (XEXP (op, 0)) == REG)
2389 || (GET_CODE (XEXP (op, 0)) == UNSPEC)))
80920132
ME
2390 {
2391 print_operand (file, XEXP (op, 0), letter);
2392 }
8cc9a5a5
EI
2393 else if (code == CONST
2394 && (GET_CODE (XEXP (op, 0)) == PLUS)
2395 && (GET_CODE (XEXP (XEXP (op, 0), 0)) == REG)
2396 && (GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST))
2397 {
2398 print_operand_address (file, XEXP (op, 0));
2399 }
80920132
ME
2400 else if (letter == 'm')
2401 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
2402 else
2403 output_addr_const (file, op);
2404}
2405
2406/* A C compound statement to output to stdio stream STREAM the
2407 assembler syntax for an instruction operand that is a memory
2408 reference whose address is ADDR. ADDR is an RTL expression.
2409
2410 Possible address classifications and output formats are,
2411
2412 ADDRESS_REG "%0, r0"
2413
2414 ADDRESS_REG with non-zero "%0, <addr_const>"
2415 offset
2416
2417 ADDRESS_REG_INDEX "rA, RB"
2418 (if rA is r0, rA and rB are swapped)
2419
2420 ADDRESS_CONST_INT "r0, <addr_const>"
2421
2422 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2423 (rBase is a base register suitable for the
2424 symbol's type)
2425*/
2426
2427void
2428print_operand_address (FILE * file, rtx addr)
2429{
2430 struct microblaze_address_info info;
2431 enum microblaze_address_type type;
2432 if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 1))
2433 fatal_insn ("insn contains an invalid address !", addr);
2434
2435 type = info.type;
2436 switch (info.type)
2437 {
2438 case ADDRESS_REG:
2439 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2440 output_addr_const (file, info.offset);
2441 break;
2442 case ADDRESS_REG_INDEX:
2443 if (REGNO (info.regA) == 0)
2444 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2445 congestion. */
2446 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2447 reg_names[REGNO (info.regA)]);
2448 else if (REGNO (info.regB) != 0)
2449 /* This is a silly swap to help Dhrystone. */
2450 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2451 reg_names[REGNO (info.regA)]);
2452 break;
2453 case ADDRESS_CONST_INT:
2454 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2455 output_addr_const (file, info.offset);
2456 break;
2457 case ADDRESS_SYMBOLIC:
2458 case ADDRESS_GOTOFF:
2459 case ADDRESS_PLT:
8cc9a5a5 2460 case ADDRESS_TLS:
80920132
ME
2461 if (info.regA)
2462 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2463 output_addr_const (file, info.symbol);
2464 if (type == ADDRESS_GOTOFF)
2465 {
2466 fputs ("@GOT", file);
2467 }
2468 else if (type == ADDRESS_PLT)
2469 {
2470 fputs ("@PLT", file);
2471 }
8cc9a5a5
EI
2472 else if (type == ADDRESS_TLS)
2473 {
2474 switch (info.tls_type)
2475 {
2476 case TLS_GD:
2477 fputs ("@TLSGD", file);
2478 break;
2479 case TLS_LDM:
2480 fputs ("@TLSLDM", file);
2481 break;
2482 case TLS_DTPREL:
2483 fputs ("@TLSDTPREL", file);
2484 break;
2485 default :
2486 abort();
2487 break;
2488 }
2489 }
80920132
ME
2490 break;
2491 case ADDRESS_INVALID:
2492 fatal_insn ("invalid address", addr);
2493 break;
2494 }
2495}
2496
2497/* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2498 is used, so that we don't emit an .extern for it in
2499 microblaze_asm_file_end. */
2500
2501void
2502microblaze_declare_object (FILE * stream, const char *name,
2503 const char *section, const char *fmt, int size)
2504{
2505
2506 fputs (section, stream);
2507 assemble_name (stream, name);
2508 fprintf (stream, fmt, size);
2509}
2510
2511/* Common code to emit the insns (or to write the instructions to a file)
2512 to save/restore registers.
2513
2514 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2515 is not modified within save_restore_insns. */
2516
2517#define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2518
2519/* Save or restore instructions based on whether this is the prologue or
2520 epilogue. prologue is 1 for the prologue. */
2521static void
2522save_restore_insns (int prologue)
2523{
2524 rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx =
2525 0, isr_mem_rtx = 0;
2526 rtx isr_msr_rtx = 0, insn;
2527 long mask = current_frame_info.mask;
556618c1 2528 HOST_WIDE_INT gp_offset;
80920132
ME
2529 int regno;
2530
2531 if (frame_pointer_needed
2532 && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
2533 gcc_unreachable ();
2534
2535 if (mask == 0)
2536 return;
2537
2538 /* Save registers starting from high to low. The debuggers prefer at least
2539 the return register be stored at func+4, and also it allows us not to
2540 need a nop in the epilog if at least one register is reloaded in
2541 addition to return address. */
2542
2543 /* Pick which pointer to use as a base register. For small frames, just
2544 use the stack pointer. Otherwise, use a temporary register. Save 2
2545 cycles if the save area is near the end of a large frame, by reusing
2546 the constant created in the prologue/epilogue to adjust the stack
2547 frame. */
2548
2549 gp_offset = current_frame_info.gp_offset;
2550
2551 gcc_assert (gp_offset > 0);
2552
2553 base_reg_rtx = stack_pointer_rtx;
80920132
ME
2554
2555 /* For interrupt_handlers, need to save/restore the MSR. */
ee61ea38 2556 if (microblaze_is_interrupt_variant ())
80920132
ME
2557 {
2558 isr_mem_rtx = gen_rtx_MEM (SImode,
2559 gen_rtx_PLUS (Pmode, base_reg_rtx,
2560 GEN_INT (current_frame_info.
2561 gp_offset -
2562 UNITS_PER_WORD)));
2563
2564 /* Do not optimize in flow analysis. */
2565 MEM_VOLATILE_P (isr_mem_rtx) = 1;
2566 isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
2567 isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
2568 }
2569
ee61ea38 2570 if (microblaze_is_interrupt_variant () && !prologue)
80920132
ME
2571 {
2572 emit_move_insn (isr_reg_rtx, isr_mem_rtx);
2573 emit_move_insn (isr_msr_rtx, isr_reg_rtx);
2574 /* Do not optimize in flow analysis. */
2575 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2576 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2577 }
2578
2579 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2580 {
2581 if (BITSET_P (mask, regno - GP_REG_FIRST))
2582 {
2583 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2584 /* Don't handle here. Already handled as the first register. */
2585 continue;
2586
2587 reg_rtx = gen_rtx_REG (SImode, regno);
2588 insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
2589 mem_rtx = gen_rtx_MEM (SImode, insn);
ee61ea38 2590 if (microblaze_is_interrupt_variant () || save_volatiles)
80920132
ME
2591 /* Do not optimize in flow analysis. */
2592 MEM_VOLATILE_P (mem_rtx) = 1;
2593
2594 if (prologue)
2595 {
2596 insn = emit_move_insn (mem_rtx, reg_rtx);
2597 RTX_FRAME_RELATED_P (insn) = 1;
2598 }
2599 else
2600 {
2601 insn = emit_move_insn (reg_rtx, mem_rtx);
2602 }
2603
2604 gp_offset += GET_MODE_SIZE (SImode);
2605 }
2606 }
2607
ee61ea38 2608 if (microblaze_is_interrupt_variant () && prologue)
80920132
ME
2609 {
2610 emit_move_insn (isr_reg_rtx, isr_msr_rtx);
2611 emit_move_insn (isr_mem_rtx, isr_reg_rtx);
2612
2613 /* Do not optimize in flow analysis. */
2614 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2615 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2616 }
2617
2618 /* Done saving and restoring */
2619}
2620
2621
2622/* Set up the stack and frame (if desired) for the function. */
2623static void
2624microblaze_function_prologue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2625{
2626 const char *fnname;
2627 long fsiz = current_frame_info.total_size;
2628
2629 /* Get the function name the same way that toplev.c does before calling
2630 assemble_start_function. This is needed so that the name used here
2631 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2632 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2633 if (!flag_inhibit_size_directive)
2634 {
2635 fputs ("\t.ent\t", file);
2636 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2637 fputs ("_interrupt_handler", file);
ee61ea38
DH
2638 else if (fast_interrupt && strcmp (FAST_INTERRUPT_NAME, fnname))
2639 fputs ("_fast_interrupt", file);
80920132
ME
2640 else
2641 assemble_name (file, fnname);
2642 fputs ("\n", file);
ee61ea38 2643 if (!microblaze_is_interrupt_variant ())
80920132
ME
2644 ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
2645 }
2646
2647 assemble_name (file, fnname);
2648 fputs (":\n", file);
2649
2650 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2651 fputs ("_interrupt_handler:\n", file);
2652
2653 if (!flag_inhibit_size_directive)
2654 {
2655 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2656 fprintf (file,
2657 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2658 (reg_names[(frame_pointer_needed)
2659 ? HARD_FRAME_POINTER_REGNUM :
2660 STACK_POINTER_REGNUM]), fsiz,
2661 reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST],
2662 current_frame_info.var_size, current_frame_info.num_gp,
2663 crtl->outgoing_args_size);
2664 fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask);
2665 }
2666}
2667
2668/* Output extra assembler code at the end of a prologue. */
2669static void
2670microblaze_function_end_prologue (FILE * file)
2671{
2672 if (TARGET_STACK_CHECK)
2673 {
2674 fprintf (file, "\t# Stack Check Stub -- Start.\n\t");
2675 fprintf (file, "ori\tr18,r0,_stack_end\n\t");
2676 fprintf (file, "cmpu\tr18,r1,r18\n\t");
2677 fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
2678 fprintf (file, "# Stack Check Stub -- End.\n");
2679 }
2680}
2681
2682/* Expand the prologue into a bunch of separate insns. */
2683
2684void
2685microblaze_expand_prologue (void)
2686{
2687 int regno;
2688 HOST_WIDE_INT fsiz;
2689 const char *arg_name = 0;
2690 tree fndecl = current_function_decl;
2691 tree fntype = TREE_TYPE (fndecl);
2692 tree fnargs = DECL_ARGUMENTS (fndecl);
2693 rtx next_arg_reg;
2694 int i;
2695 tree next_arg;
2696 tree cur_arg;
d5cc9181
JR
2697 CUMULATIVE_ARGS args_so_far_v;
2698 cumulative_args_t args_so_far;
80920132
ME
2699 rtx mem_rtx, reg_rtx;
2700
2701 /* If struct value address is treated as the first argument, make it so. */
2702 if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
2703 && !cfun->returns_pcc_struct)
2704 {
2705 tree type = build_pointer_type (fntype);
2706 tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL,
2707 NULL_TREE, type);
2708
2709 DECL_ARG_TYPE (function_result_decl) = type;
2710 TREE_CHAIN (function_result_decl) = fnargs;
2711 fnargs = function_result_decl;
2712 }
2713
2714 /* Determine the last argument, and get its name. */
2715
d5cc9181
JR
2716 INIT_CUMULATIVE_ARGS (args_so_far_v, fntype, NULL_RTX, 0, 0);
2717 args_so_far = pack_cumulative_args (&args_so_far_v);
80920132
ME
2718 regno = GP_ARG_FIRST;
2719
2720 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
2721 {
2722 tree passed_type = DECL_ARG_TYPE (cur_arg);
2723 enum machine_mode passed_mode = TYPE_MODE (passed_type);
2724 rtx entry_parm;
2725
2726 if (TREE_ADDRESSABLE (passed_type))
2727 {
2728 passed_type = build_pointer_type (passed_type);
2729 passed_mode = Pmode;
2730 }
2731
d5cc9181 2732 entry_parm = targetm.calls.function_arg (args_so_far, passed_mode,
5239874d 2733 passed_type, true);
80920132
ME
2734
2735 if (entry_parm)
2736 {
2737 int words;
2738
2739 /* passed in a register, so will get homed automatically. */
2740 if (GET_MODE (entry_parm) == BLKmode)
2741 words = (int_size_in_bytes (passed_type) + 3) / 4;
2742 else
2743 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
2744
2745 regno = REGNO (entry_parm) + words - 1;
2746 }
2747 else
2748 {
2749 regno = GP_ARG_LAST + 1;
2750 break;
2751 }
2752
d5cc9181 2753 targetm.calls.function_arg_advance (args_so_far, passed_mode,
5239874d 2754 passed_type, true);
80920132
ME
2755
2756 next_arg = TREE_CHAIN (cur_arg);
2757 if (next_arg == 0)
2758 {
2759 if (DECL_NAME (cur_arg))
2760 arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
2761
2762 break;
2763 }
2764 }
2765
2766 /* Split parallel insn into a sequence of insns. */
2767
d5cc9181 2768 next_arg_reg = targetm.calls.function_arg (args_so_far, VOIDmode,
5239874d 2769 void_type_node, true);
80920132
ME
2770 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
2771 {
2772 rtvec adjust = XVEC (next_arg_reg, 0);
2773 int num = GET_NUM_ELEM (adjust);
2774
2775 for (i = 0; i < num; i++)
2776 {
2777 rtx pattern = RTVEC_ELT (adjust, i);
2778 emit_insn (pattern);
2779 }
2780 }
2781
2782 fsiz = compute_frame_size (get_frame_size ());
2783
9b69d4b4 2784 if (flag_stack_usage_info)
b950ac25
DH
2785 current_function_static_stack_size = fsiz;
2786
80920132
ME
2787 /* If this function is a varargs function, store any registers that
2788 would normally hold arguments ($5 - $10) on the stack. */
2789 if (((TYPE_ARG_TYPES (fntype) != 0
2790 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2791 != void_type_node))
2792 || (arg_name != 0
2793 && ((arg_name[0] == '_'
2794 && strcmp (arg_name, "__builtin_va_alist") == 0)
2795 || (arg_name[0] == 'v'
2796 && strcmp (arg_name, "va_alist") == 0)))))
2797 {
2798 int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD;
2799 rtx ptr = stack_pointer_rtx;
2800
2801 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2802 for (; regno <= GP_ARG_LAST; regno++)
2803 {
2804 if (offset != 0)
2805 ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
2806 emit_move_insn (gen_rtx_MEM (SImode, ptr),
2807 gen_rtx_REG (SImode, regno));
2808
2809 offset += GET_MODE_SIZE (SImode);
2810 }
2811
2812 }
2813
2814 if (fsiz > 0)
2815 {
2816 rtx fsiz_rtx = GEN_INT (fsiz);
2817
2818 rtx insn = NULL;
2819 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
2820 fsiz_rtx));
2821 if (insn)
2822 RTX_FRAME_RELATED_P (insn) = 1;
2823
2824 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
416ff32e 2825 if (!crtl->is_leaf || interrupt_handler)
80920132
ME
2826 {
2827 mem_rtx = gen_rtx_MEM (SImode,
2828 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2829 const0_rtx));
2830
2831 if (interrupt_handler)
2832 /* Do not optimize in flow analysis. */
2833 MEM_VOLATILE_P (mem_rtx) = 1;
2834
2835 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2836 insn = emit_move_insn (mem_rtx, reg_rtx);
2837 RTX_FRAME_RELATED_P (insn) = 1;
2838 }
2839
2840 /* _save_ registers for prologue. */
2841 save_restore_insns (1);
2842
2843 if (frame_pointer_needed)
2844 {
2845 rtx insn = 0;
2846
2847 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
2848 stack_pointer_rtx));
2849
2850 if (insn)
2851 RTX_FRAME_RELATED_P (insn) = 1;
2852 }
2853 }
2854
8cc9a5a5
EI
2855 if ((flag_pic == 2 || TLS_NEEDS_GOT )
2856 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
80920132 2857 {
80920132 2858 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
556618c1 2859 emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */
80920132
ME
2860 }
2861
2862 /* If we are profiling, make sure no instructions are scheduled before
2863 the call to mcount. */
2864
2865 if (profile_flag)
2866 emit_insn (gen_blockage ());
2867}
2868
2869/* Do necessary cleanup after a function to restore stack, frame, and regs. */
2870
2871#define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2872#define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2873
2874static void
2875microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED,
2876 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2877{
2878 const char *fnname;
2879
2880 /* Get the function name the same way that toplev.c does before calling
2881 assemble_start_function. This is needed so that the name used here
2882 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2883 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2884
2885 if (!flag_inhibit_size_directive)
2886 {
2887 fputs ("\t.end\t", file);
2888 if (interrupt_handler)
2889 fputs ("_interrupt_handler", file);
2890 else
2891 assemble_name (file, fnname);
2892 fputs ("\n", file);
2893 }
2894
2895 /* Reset state info for each function. */
2896 current_frame_info = zero_frame_info;
2897
2898 /* Restore the output file if optimizing the GP (optimizing the GP causes
2899 the text to be diverted to a tempfile, so that data decls come before
2900 references to the data). */
2901}
2902
2903/* Expand the epilogue into a bunch of separate insns. */
2904
2905void
2906microblaze_expand_epilogue (void)
2907{
2908 HOST_WIDE_INT fsiz = current_frame_info.total_size;
2909 rtx fsiz_rtx = GEN_INT (fsiz);
2910 rtx reg_rtx;
2911 rtx mem_rtx;
2912
2913 /* In case of interrupt handlers use addki instead of addi for changing the
2914 stack pointer value. */
2915
2916 if (microblaze_can_use_return_insn ())
2917 {
2918 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
2919 GP_REG_FIRST +
2920 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2921 return;
2922 }
2923
2924 if (fsiz > 0)
2925 {
2926 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
2927 sequence of load-followed by a use (in rtsd) in every prologue. Saves
2928 a load-use stall cycle :) This is also important to handle alloca.
2929 (See comments for if (frame_pointer_needed) below. */
2930
416ff32e 2931 if (!crtl->is_leaf || interrupt_handler)
80920132
ME
2932 {
2933 mem_rtx =
2934 gen_rtx_MEM (SImode,
2935 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
2936 if (interrupt_handler)
2937 /* Do not optimize in flow analysis. */
2938 MEM_VOLATILE_P (mem_rtx) = 1;
2939 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2940 emit_move_insn (reg_rtx, mem_rtx);
2941 }
2942
2943 /* It is important that this is done after we restore the return address
2944 register (above). When alloca is used, we want to restore the
2945 sub-routine return address only from the current stack top and not
2946 from the frame pointer (which we restore below). (frame_pointer + 0)
2947 might have been over-written since alloca allocates memory on the
2948 current stack. */
2949 if (frame_pointer_needed)
2950 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
2951
2952 /* _restore_ registers for epilogue. */
2953 save_restore_insns (0);
2954 emit_insn (gen_blockage ());
2955 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
2956 }
2957
2958 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
2959 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2960}
2961
2962
2963/* Return nonzero if this function is known to have a null epilogue.
2964 This allows the optimizer to omit jumps to jumps if no stack
2965 was created. */
2966
2967int
2968microblaze_can_use_return_insn (void)
2969{
2970 if (!reload_completed)
2971 return 0;
2972
2973 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag)
2974 return 0;
2975
2976 if (current_frame_info.initialized)
2977 return current_frame_info.total_size == 0;
2978
2979 return compute_frame_size (get_frame_size ()) == 0;
2980}
2981
2982/* Implement TARGET_SECONDARY_RELOAD. */
2983
556618c1 2984static reg_class_t
80920132 2985microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
556618c1 2986 reg_class_t rclass, enum machine_mode mode ATTRIBUTE_UNUSED,
80920132
ME
2987 secondary_reload_info *sri ATTRIBUTE_UNUSED)
2988{
2989 if (rclass == ST_REGS)
2990 return GR_REGS;
2991
2992 return NO_REGS;
2993}
2994
2995static void
2996microblaze_globalize_label (FILE * stream, const char *name)
2997{
2998 fputs ("\t.globl\t", stream);
ee61ea38 2999 if (microblaze_is_interrupt_variant ())
80920132 3000 {
ee61ea38
DH
3001 if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
3002 fputs (INTERRUPT_HANDLER_NAME, stream);
3003 else if (fast_interrupt && strcmp (name, FAST_INTERRUPT_NAME))
3004 fputs (FAST_INTERRUPT_NAME, stream);
80920132
ME
3005 fputs ("\n\t.globl\t", stream);
3006 }
3007 assemble_name (stream, name);
3008 fputs ("\n", stream);
3009}
3010
3011/* Returns true if decl should be placed into a "small data" section. */
3012static bool
3013microblaze_elf_in_small_data_p (const_tree decl)
3014{
556618c1
JR
3015 HOST_WIDE_INT size;
3016
80920132
ME
3017 if (!TARGET_XLGPOPT)
3018 return false;
3019
3020 /* We want to merge strings, so we never consider them small data. */
3021 if (TREE_CODE (decl) == STRING_CST)
3022 return false;
3023
3024 /* Functions are never in the small data area. */
3025 if (TREE_CODE (decl) == FUNCTION_DECL)
3026 return false;
3027
3028 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
3029 {
3030 const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
3031 if (strcmp (section, ".sdata") == 0
3032 || strcmp (section, ".sdata2") == 0
3033 || strcmp (section, ".sbss") == 0
3034 || strcmp (section, ".sbss2") == 0)
3035 return true;
3036 }
3037
556618c1 3038 size = int_size_in_bytes (TREE_TYPE (decl));
80920132
ME
3039
3040 return (size > 0 && size <= microblaze_section_threshold);
3041}
3042
3043
3044static section *
3045microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
3046{
3047 switch (categorize_decl_for_section (decl, reloc))
3048 {
3049 case SECCAT_RODATA_MERGE_STR:
3050 case SECCAT_RODATA_MERGE_STR_INIT:
3051 /* MB binutils have various issues with mergeable string sections and
3052 relaxation/relocation. Currently, turning mergeable sections
3053 into regular readonly sections. */
3054
3055 return readonly_data_section;
3056 default:
3057 return default_elf_select_section (decl, reloc, align);
3058 }
3059}
3060
3061/*
3062 Encode info about sections into the RTL based on a symbol's declaration.
3063 The default definition of this hook, default_encode_section_info in
3064 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3065
3066static void
3067microblaze_encode_section_info (tree decl, rtx rtl, int first)
3068{
3069 default_encode_section_info (decl, rtl, first);
3070}
3071
3072static rtx
3073expand_pic_symbol_ref (enum machine_mode mode ATTRIBUTE_UNUSED, rtx op)
3074{
3075 rtx result;
3076 result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF);
3077 result = gen_rtx_CONST (Pmode, result);
3078 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
3079 result = gen_const_mem (Pmode, result);
3080 return result;
3081}
3082
3083bool
3084microblaze_expand_move (enum machine_mode mode, rtx operands[])
3085{
8cc9a5a5
EI
3086 rtx op0, op1;
3087
3088 op0 = operands[0];
3089 op1 = operands[1];
3090
3091 if (!register_operand (op0, SImode)
3092 && !register_operand (op1, SImode)
3093 && (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0))
3094 {
3095 rtx temp = force_reg (SImode, op1);
3096 emit_move_insn (op0, temp);
3097 return true;
3098 }
80920132
ME
3099 /* If operands[1] is a constant address invalid for pic, then we need to
3100 handle it just like LEGITIMIZE_ADDRESS does. */
8cc9a5a5 3101 if (GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF)
80920132 3102 {
8cc9a5a5
EI
3103 rtx result;
3104 if (microblaze_tls_symbol_p(op1))
80920132 3105 {
8cc9a5a5
EI
3106 result = microblaze_legitimize_tls_address (op1, NULL_RTX);
3107 emit_move_insn (op0, result);
3108 return true;
80920132 3109 }
8cc9a5a5 3110 else if (flag_pic)
80920132 3111 {
80920132
ME
3112 if (reload_in_progress)
3113 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
8cc9a5a5
EI
3114 result = expand_pic_symbol_ref (mode, op1);
3115 emit_move_insn (op0, result);
80920132
ME
3116 return true;
3117 }
8cc9a5a5
EI
3118 }
3119 /* Handle Case of (const (plus symbol const_int)). */
3120 if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1,0)) == PLUS)
3121 {
3122 rtx p0, p1;
80920132 3123
8cc9a5a5
EI
3124 p0 = XEXP (XEXP (op1, 0), 0);
3125 p1 = XEXP (XEXP (op1, 0), 1);
80920132 3126
8cc9a5a5
EI
3127 if ((GET_CODE (p1) == CONST_INT)
3128 && ((GET_CODE (p0) == UNSPEC)
3129 || ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3130 && (flag_pic == 2 || microblaze_tls_symbol_p (p0)
3131 || !SMALL_INT (p1)))))
80920132 3132 {
8cc9a5a5
EI
3133 rtx temp = force_reg (SImode, p0);
3134 rtx temp2 = p1;
80920132 3135
8cc9a5a5 3136 if (flag_pic && reload_in_progress)
80920132 3137 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
8cc9a5a5 3138 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, temp2));
80920132
ME
3139 return true;
3140 }
3141 }
80920132
ME
3142 return false;
3143}
3144
3145/* Expand shift operations. */
3146int
3147microblaze_expand_shift (rtx operands[])
3148{
3149 gcc_assert ((GET_CODE (operands[2]) == CONST_INT)
3150 || (GET_CODE (operands[2]) == REG)
3151 || (GET_CODE (operands[2]) == SUBREG));
3152
3153 /* Shift by one -- generate pattern. */
3154 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1))
3155 return 0;
3156
3157 /* Have barrel shifter and shift > 1: use it. */
3158 if (TARGET_BARREL_SHIFT)
3159 return 0;
3160
3161 gcc_assert ((GET_CODE (operands[0]) == REG)
3162 || (GET_CODE (operands[0]) == SUBREG)
3163 || (GET_CODE (operands[1]) == REG)
3164 || (GET_CODE (operands[1]) == SUBREG));
3165
3166 /* Shift by zero -- copy regs if necessary. */
3167 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 0))
3168 {
3169 if (REGNO (operands[0]) != REGNO (operands[1]))
3170 emit_insn (gen_movsi (operands[0], operands[1]));
3171 return 1;
3172 }
3173
3174 return 0;
3175}
3176
3177/* Return an RTX indicating where the return address to the
3178 calling function can be found. */
3179rtx
3180microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
3181{
3182 if (count != 0)
3183 return NULL_RTX;
3184
3185 return gen_rtx_PLUS (Pmode,
3186 get_hard_reg_initial_val (Pmode,
3187 MB_ABI_SUB_RETURN_ADDR_REGNUM),
3188 GEN_INT (8));
3189}
3190
a8781821
SB
3191/* Queue an .ident string in the queue of top-level asm statements.
3192 If the string size is below the threshold, put it into .sdata2.
3193 If the front-end is done, we must be being called from toplev.c.
3194 In that case, do nothing. */
80920132 3195void
a8781821 3196microblaze_asm_output_ident (const char *string)
80920132 3197{
a8781821
SB
3198 const char *section_asm_op;
3199 int size;
3200 char *buf;
3201
3202 if (cgraph_state != CGRAPH_STATE_PARSING)
3203 return;
3204
3205 size = strlen (string) + 1;
80920132 3206 if (size <= microblaze_section_threshold)
a8781821 3207 section_asm_op = SDATA2_SECTION_ASM_OP;
80920132 3208 else
a8781821
SB
3209 section_asm_op = READONLY_DATA_SECTION_ASM_OP;
3210
3211 buf = ACONCAT ((section_asm_op, "\n\t.ascii \"", string, "\\0\"\n", NULL));
3212 add_asm_node (build_string (strlen (buf), buf));
80920132
ME
3213}
3214
3215static void
3216microblaze_elf_asm_init_sections (void)
3217{
3218 sdata2_section
3219 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
3220 SDATA2_SECTION_ASM_OP);
3221}
3222
3223/* Generate assembler code for constant parts of a trampoline. */
3224
3225static void
3226microblaze_asm_trampoline_template (FILE *f)
3227{
8ec77be0
EI
3228 fprintf (f, "\tmfs r18, rpc\n");
3229 fprintf (f, "\tlwi r3, r18, 16\n");
3230 fprintf (f, "\tlwi r18, r18, 20\n");
3231 fprintf (f, "\tbra r18\n");
80920132
ME
3232 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3233 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3234}
3235
3236/* Implement TARGET_TRAMPOLINE_INIT. */
3237
3238static void
3239microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
3240{
3241 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
3242 rtx mem;
3243
3244 emit_block_move (m_tramp, assemble_trampoline_template (),
8ec77be0 3245 GEN_INT (6*UNITS_PER_WORD), BLOCK_OP_NORMAL);
80920132 3246
8ec77be0 3247 mem = adjust_address (m_tramp, SImode, 16);
80920132 3248 emit_move_insn (mem, chain_value);
8ec77be0 3249 mem = adjust_address (m_tramp, SImode, 20);
80920132
ME
3250 emit_move_insn (mem, fnaddr);
3251}
3252\f
3253/* Emit instruction to perform compare.
3254 cmp is (compare_op op0 op1). */
3255static rtx
3256microblaze_emit_compare (enum machine_mode mode, rtx cmp, enum rtx_code *cmp_code)
3257{
3258 rtx cmp_op0 = XEXP (cmp, 0);
3259 rtx cmp_op1 = XEXP (cmp, 1);
3260 rtx comp_reg = gen_reg_rtx (SImode);
3261 enum rtx_code code = *cmp_code;
3262
3263 gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
3264
3265 /* If comparing against zero, just test source reg. */
3266 if (cmp_op1 == const0_rtx)
3267 return cmp_op0;
3268
3269 if (code == EQ || code == NE)
3270 {
bbb3a9e2
EI
3271 /* Use xor for equal/not-equal comparison. */
3272 emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
80920132
ME
3273 }
3274 else if (code == GT || code == GTU || code == LE || code == LEU)
3275 {
3276 /* MicroBlaze compare is not symmetrical. */
3277 /* Swap argument order. */
3278 cmp_op1 = force_reg (mode, cmp_op1);
3279 if (code == GT || code == LE)
3280 emit_insn (gen_signed_compare (comp_reg, cmp_op0, cmp_op1));
3281 else
3282 emit_insn (gen_unsigned_compare (comp_reg, cmp_op0, cmp_op1));
3283 /* Translate test condition. */
3284 *cmp_code = swap_condition (code);
3285 }
3286 else /* if (code == GE || code == GEU || code == LT || code == LTU) */
3287 {
3288 cmp_op1 = force_reg (mode, cmp_op1);
3289 if (code == GE || code == LT)
3290 emit_insn (gen_signed_compare (comp_reg, cmp_op1, cmp_op0));
3291 else
3292 emit_insn (gen_unsigned_compare (comp_reg, cmp_op1, cmp_op0));
3293 }
3294
3295 return comp_reg;
3296}
3297
3298/* Generate conditional branch -- first, generate test condition,
3299 second, generate correct branch instruction. */
3300
3301void
3302microblaze_expand_conditional_branch (enum machine_mode mode, rtx operands[])
3303{
3304 enum rtx_code code = GET_CODE (operands[0]);
3305 rtx comp;
3306 rtx condition;
3307
3308 comp = microblaze_emit_compare (mode, operands[0], &code);
3309 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp, const0_rtx);
3310 emit_jump_insn (gen_condjump (condition, operands[3]));
3311}
3312
3313void
3314microblaze_expand_conditional_branch_sf (rtx operands[])
3315{
3316 rtx condition;
3317 rtx cmp_op0 = XEXP (operands[0], 0);
3318 rtx cmp_op1 = XEXP (operands[0], 1);
3319 rtx comp_reg = gen_reg_rtx (SImode);
3320
3321 emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1));
3322 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3323 emit_jump_insn (gen_condjump (condition, operands[3]));
3324}
3325
3326/* Implement TARGET_FRAME_POINTER_REQUIRED. */
3327
3328static bool
3329microblaze_frame_pointer_required (void)
3330{
3331 /* If the function contains dynamic stack allocations, we need to
3332 use the frame pointer to access the static parts of the frame. */
3333 if (cfun->calls_alloca)
3334 return true;
3335 return false;
3336}
3337
3338void
3339microblaze_expand_divide (rtx operands[])
3340{
3341 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3342
3343 rtx regt1 = gen_reg_rtx (SImode);
3344 rtx reg18 = gen_rtx_REG (SImode, R_TMP);
3345 rtx regqi = gen_reg_rtx (QImode);
3346 rtx div_label = gen_label_rtx ();
3347 rtx div_end_label = gen_label_rtx ();
3348 rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
3349 rtx mem_rtx;
3350 rtx ret;
3351 rtx jump, cjump, insn;
3352
3353 insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
3354 cjump = emit_jump_insn_after (gen_cbranchsi4 (
3355 gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
3356 regt1, GEN_INT (15), div_label), insn);
3357 LABEL_NUSES (div_label) = 1;
3358 JUMP_LABEL (cjump) = div_label;
3359 emit_insn (gen_rtx_CLOBBER (SImode, reg18));
3360
3361 emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4)));
3362 emit_insn (gen_addsi3 (regt1, regt1, operands[2]));
3363 mem_rtx = gen_rtx_MEM (QImode,
3364 gen_rtx_PLUS (Pmode, regt1, div_table_rtx));
3365
3366 insn = emit_insn (gen_movqi (regqi, mem_rtx));
3367 insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0)));
3368 jump = emit_jump_insn_after (gen_jump (div_end_label), insn);
3369 JUMP_LABEL (jump) = div_end_label;
3370 LABEL_NUSES (div_end_label) = 1;
3371 emit_barrier ();
3372
3373 emit_label (div_label);
3374 ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
3375 operands[0], LCT_NORMAL,
3376 GET_MODE (operands[0]), 2, operands[1],
3377 GET_MODE (operands[1]), operands[2],
3378 GET_MODE (operands[2]));
3379 if (ret != operands[0])
3380 emit_move_insn (operands[0], ret);
3381
3382 emit_label (div_end_label);
3383 emit_insn (gen_blockage ());
3384}
3385
3386/* Implement TARGET_FUNCTION_VALUE. */
3387static rtx
3388microblaze_function_value (const_tree valtype,
3389 const_tree func ATTRIBUTE_UNUSED,
3390 bool outgoing ATTRIBUTE_UNUSED)
3391{
3392 return LIBCALL_VALUE (TYPE_MODE (valtype));
3393}
3394
3395/* Implement TARGET_SCHED_ADJUST_COST. */
3396static int
3397microblaze_adjust_cost (rtx insn ATTRIBUTE_UNUSED, rtx link,
3398 rtx dep ATTRIBUTE_UNUSED, int cost)
3399{
3400 if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
3401 return cost;
3402 if (REG_NOTE_KIND (link) != 0)
3403 return 0;
3404 return cost;
3405}
1a627b35
RS
3406
3407/* Implement TARGET_LEGITIMATE_CONSTANT_P.
3408
3409 At present, GAS doesn't understand li.[sd], so don't allow it
3410 to be generated at present. */
3411static bool
8cc9a5a5 3412microblaze_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
1a627b35 3413{
8cc9a5a5
EI
3414
3415 if (microblaze_cannot_force_const_mem(mode, x))
3416 return false;
3417
3418 if (GET_CODE (x) == CONST_DOUBLE)
3419 {
3420 return microblaze_const_double_ok (x, GET_MODE (x));
3421 }
3422
3423 /* Handle Case of (const (plus unspec const_int)). */
3424 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
3425 {
3426 rtx p0, p1;
3427
3428 p0 = XEXP (XEXP (x, 0), 0);
3429 p1 = XEXP (XEXP (x, 0), 1);
3430
3431 if (GET_CODE(p1) == CONST_INT)
3432 {
3433 /* Const offset from UNSPEC is not supported. */
3434 if ((GET_CODE (p0) == UNSPEC))
3435 return false;
3436
3437 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3438 && (microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
3439 return false;
3440 }
3441 }
3442
3443 return true;
1a627b35 3444}
8cc9a5a5 3445
80920132
ME
3446\f
3447#undef TARGET_ENCODE_SECTION_INFO
3448#define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3449
3450#undef TARGET_ASM_GLOBALIZE_LABEL
3451#define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3452
3453#undef TARGET_ASM_FUNCTION_PROLOGUE
3454#define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3455
3456#undef TARGET_ASM_FUNCTION_EPILOGUE
3457#define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3458
3459#undef TARGET_RTX_COSTS
3460#define TARGET_RTX_COSTS microblaze_rtx_costs
3461
8cc9a5a5
EI
3462#undef TARGET_CANNOT_FORCE_CONST_MEM
3463#define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3464
80920132
ME
3465#undef TARGET_ADDRESS_COST
3466#define TARGET_ADDRESS_COST microblaze_address_cost
3467
3468#undef TARGET_ATTRIBUTE_TABLE
3469#define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3470
3471#undef TARGET_IN_SMALL_DATA_P
3472#define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3473
3474#undef TARGET_ASM_SELECT_SECTION
3475#define TARGET_ASM_SELECT_SECTION microblaze_select_section
3476
3477#undef TARGET_HAVE_SRODATA_SECTION
3478#define TARGET_HAVE_SRODATA_SECTION true
3479
3480#undef TARGET_ASM_FUNCTION_END_PROLOGUE
3481#define TARGET_ASM_FUNCTION_END_PROLOGUE \
3482 microblaze_function_end_prologue
3483
80920132
ME
3484#undef TARGET_ARG_PARTIAL_BYTES
3485#define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3486
5239874d
NF
3487#undef TARGET_FUNCTION_ARG
3488#define TARGET_FUNCTION_ARG microblaze_function_arg
3489
3490#undef TARGET_FUNCTION_ARG_ADVANCE
3491#define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3492
80920132
ME
3493#undef TARGET_CAN_ELIMINATE
3494#define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3495
3496#undef TARGET_LEGITIMIZE_ADDRESS
3497#define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3498
3499#undef TARGET_LEGITIMATE_ADDRESS_P
3500#define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3501
3502#undef TARGET_FRAME_POINTER_REQUIRED
3503#define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3504
3505#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3506#define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3507
3508#undef TARGET_TRAMPOLINE_INIT
3509#define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3510
3511#undef TARGET_PROMOTE_FUNCTION_MODE
3512#define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3513
3514#undef TARGET_FUNCTION_VALUE
3515#define TARGET_FUNCTION_VALUE microblaze_function_value
3516
3517#undef TARGET_SECONDARY_RELOAD
3518#define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3519
3520#undef TARGET_SCHED_ADJUST_COST
3521#define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3522
3523#undef TARGET_ASM_INIT_SECTIONS
3524#define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3525
3526#undef TARGET_OPTION_OVERRIDE
3527#define TARGET_OPTION_OVERRIDE microblaze_option_override
3528
1a627b35
RS
3529#undef TARGET_LEGITIMATE_CONSTANT_P
3530#define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3531
80920132
ME
3532struct gcc_target targetm = TARGET_INITIALIZER;
3533\f
3534#include "gt-microblaze.h"